<jupyter_start><jupyter_text>**`@property`**  Simple getter and setter.<jupyter_code>>>> class Foo(object):
...     def __init__(self, x):
...         self.__x = x
...     def getX(self):
...         return self.__x
...     def setX(self, x):
...         self.__x = x
foo = Foo(5)
foo.getX()
foo.setX(10)
foo.getX()<jupyter_output><empty_output><jupyter_text>Python way of defining is much simpler.<jupyter_code>>>> class Foo(object):
...     def __init__(self, x):
...         self.x = x
foo = Foo(5); foo.x
foo.x = 10
foo.x<jupyter_output><empty_output><jupyter_text>**Where is data ENCAPSULATION?** getX and setX in our starting example did was **getting the data through** without doing anything, no checks nothing.What happens, if we want to change the implementation in the future?Lets change the implementation, as following:- The attribute **x** can have values between **0** and **1000**- If a value larger than **1000** is assigned, **x** should be set to **1000**- **x** should be set to **0**, if the value is less than **0**<jupyter_code>>>> class Foo(object):
...     def __init__(self,x):
...         self.__x = x
...     def getX(self):
...         return self.__x
...     def setX(self, x):
...         if x < 0:
...             self.__x = 0
...         elif x > 1000:
...             self.__x = 1000
...         else:
...             self.__x = x
...     def delX(self):
...         del self.__x
foo = Foo(5)
foo.getX()
foo.setX(1010)
foo.getX()
foo.setX(-1)
foo.getX()<jupyter_output><empty_output><jupyter_text>People recommended to use only private attributes with getters and setters, so that they can change the implementation without having to change the interface.Let's assume we have designed our class with the public attribute and no methods. People have already used it a lot and they have written code like this:***```from foo_module import foofoo = Foo(100)foo.x = 1001```***<jupyter_code>>>> class Foo(object):
...     def __init__(self):
...         self.__x = None
...     def getX(self):
...         return self.__x
...     def setX(self, x):
...         if x < 0:
...             self.__x = 0
...         elif x > 1000:
...             self.__x = 1000
...         else:
...             self.__x = x
...     def delX(self):
...         del self.__x
...     x = property(getX,   setX,   delX,    "I'm the 'x' property.")
...               # (getter, setter, deleter, doc_string)
foo = Foo()
foo
foo.x = 100
foo.x
foo.x = 1010
foo.x
foo.x = -1
foo.x
del foo.x
foo.x
foo
foo.x = 2000
foo.x<jupyter_output><empty_output><jupyter_text>The **`@property`** decorator turns the method into a **`getter`** for a read-only attribute with the same name.A property object has `getter`, `setter`, and `deleter` methods usable as decorators that create a copy of the property with the corresponding accessor function set to the decorated function. This is best explained with an example:<jupyter_code>>>> class Foo(object):
...     def __init__(self):
...         self.__x = None
...     @property
...     def x(self):
...         return self.__x
...     @x.setter
...     def x(self, x):
...         if x < 0:
...             self.__x = 0
...         elif x > 1000:
...             self.__x = 1000
...         else:
...             self.__x = x
...     @x.deleter
...     def x(self):
...         del self.__x
foo = Foo()
foo.x = 1010
foo.x
foo.x = 100
foo.x
foo.x = -1
foo.x
del foo.x
foo.x<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.15742085390647692, 'fraction_numerical': 0.02439732791170491, 'mean_word_length': 2.212686567164179, 'pattern_counts': {'":': 0, '<': 24, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '44652', 'license': 'MIT', 'n_tokens_mistral': 1208, 'n_tokens_neox': 1116, 'n_words': 371, 'path': '00-PythonLearning/01-Tutorials/python_examples/class_properties.ipynb', 'repo_name': 'spendyala/deeplearning-docker', 'size': '3443'}