{"id":6181,"date":"2020-05-31T06:22:06","date_gmt":"2020-05-31T06:22:06","guid":{"rendered":"https:\/\/www.askpython.com\/?p=6181"},"modified":"2021-06-21T07:32:41","modified_gmt":"2021-06-21T07:32:41","slug":"python-property-decorator","status":"publish","type":"post","link":"https:\/\/www.askpython.com\/python\/built-in-methods\/python-property-decorator","title":{"rendered":"How to Use Python Property Decorator?"},"content":{"rendered":"\n<p>Hello again! In this article, we&#8217;ll be taking a look at Python property decorator.<\/p>\n\n\n\n<p>Python has a very useful feature called decorators, which is just a syntactic sugar for function-wrappers. Here, we&#8217;ll be focusing on the property decorator, which is a special type of decorator.<\/p>\n\n\n\n<p>This topic may be a bit confusing to you, so we&#8217;ll cover it step-by-step, using illustrative examples. Let&#8217;s get started!<\/p>\n\n\n\n<hr class=\"wp-block-separator has-text-color has-background has-vivid-green-cyan-background-color has-vivid-green-cyan-color\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">What is the Python Property Decorator based on?<\/h2>\n\n\n\n<p>The Property decorator is based on the in-built <code>property()<\/code> function. This function returns a special <code>property<\/code> object.<\/p>\n\n\n\n<p>You can call this in your Python Interpreter and take a look:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n&gt;&gt;&gt; property()\n&lt;property object at 0x000002BBD7302BD8&gt;\n<\/pre><\/div>\n\n\n<p>This <code>property<\/code> object has some extra methods, for getting and setting the values of the object. It also has a method for deleting it.<\/p>\n\n\n\n<p>The list of methods is given below:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><code>property().getter<\/code><\/li><li><code>property().setter<\/code><\/li><li><code>property().deleter<\/code><\/li><\/ul>\n\n\n\n<p>But it does not stop there! These methods can be used on other objects too, and act as decorators themselves!<\/p>\n\n\n\n<p>So, for example, we can use <code>property().getter(obj)<\/code>, which will give us another property object!<\/p>\n\n\n\n<p>So, the thing to note is that the property decorator will use this function, which will have some special methods for reading and writing to the object. But how does that help us?<\/p>\n\n\n\n<p>Let&#8217;s take a look now.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-text-color has-background has-vivid-green-cyan-background-color has-vivid-green-cyan-color\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Using the Python Property Decorator<\/h2>\n\n\n\n<p>To use the property decorator, we need to wrap it around any function \/ method.<\/p>\n\n\n\n<p>Here&#8217;s a simple example:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n@property\ndef fun(a, b):\n    return a + b\n<\/pre><\/div>\n\n\n<p>This is the same as:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\ndef fun(a, b):\n    return a + b\n\nfun = property(fun)\n<\/pre><\/div>\n\n\n<p>So here, we wrap <code>property()<\/code> around <code>fun()<\/code>, which is exactly what a decorator does!<\/p>\n\n\n\n<p>Let&#8217;s now take a simple example, by using the property decorator on a class method.<\/p>\n\n\n\n<p>Consider the below class, without the any decorated methods:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nclass Student():\n    def __init__(self, name, id):\n        self.name = name\n        self.id = id\n        self.full_id = self.name + &quot; - &quot; + str(self.id)\n\n    def get_name(self):\n        return self.name\n\ns = Student(&quot;Amit&quot;, 10)\nprint(s.name)\nprint(s.full_id)\n\n# Change only the name\ns.name = &quot;Rahul&quot;\nprint(s.name)\nprint(s.full_id)\n<\/pre><\/div>\n\n\n<p><strong>Output<\/strong><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nAmit\nAmit - 10\nRahul\nAmit - 10\n<\/pre><\/div>\n\n\n<p>Here, as you can see, when we only change the <code>name<\/code> attribute of our object, it&#8217;s reference to the <code>full_id<\/code> attribute is still not updated!<\/p>\n\n\n\n<p>To ensure that the <code>full_id<\/code> attribute also gets updated whenever <code>name<\/code> or <code>id<\/code> gets updated, one solution could be to make <code>full_id<\/code> into a method instead.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nclass Student():\n    def __init__(self, name, id):\n        self.name = name\n        self.id = id\n\n    def get_name(self):\n        return self.name\n\n    # Convert full_id into a method\n    def full_id(self):\n        return self.name + &quot; - &quot; + str(self.id)\n\ns = Student(&quot;Amit&quot;, 10)\nprint(s.name)\n# Method call\nprint(s.full_id())\n\ns.name = &quot;Rahul&quot;\nprint(s.name)\n# Method call\nprint(s.full_id())\n<\/pre><\/div>\n\n\n<p><strong>Output<\/strong><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nAmit\nAmit - 10\nRahul\nRahul - 10\n<\/pre><\/div>\n\n\n<p>Here, we have solved our problem by converting <code>full_id<\/code> into a method <code>full_id()<\/code>.<\/p>\n\n\n\n<p>However, this is not the best way to tackle this problem, since you may need to convert all such attributes into a method instead, and change the attributes into method calls. This is not convenient!<\/p>\n\n\n\n<p>To reduce our pain, we can use the <code>@property<\/code> decorator instead!<\/p>\n\n\n\n<p>The idea is to make <code>full_id()<\/code> into a method, but enclose it using <code>@property<\/code>. This way, we would be able to update the <code>full_id<\/code>, without having to treat it as a function call.<\/p>\n\n\n\n<p>We can directly do this : <code>s.full_id<\/code>. Notice that there is no method call here. This is because of the property decorator.<\/p>\n\n\n\n<p>Let&#8217;s try this out now!<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nclass Student():\n    def __init__(self, name, id):\n        self.name = name\n        self.id = id\n\n    def get_name(self):\n        return self.name\n\n    @property\n    def full_id(self):\n        return self.name + &quot; - &quot; + str(self.id)\n\ns = Student(&quot;Amit&quot;, 10)\nprint(s.name)\n# No more method calls!\nprint(s.full_id)\n\ns.name = &quot;Rahul&quot;\nprint(s.name)\n# No more method calls!\nprint(s.full_id)\n<\/pre><\/div>\n\n\n<p><strong>Output<\/strong><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nAmit\nAmit - 10\nRahul\nRahul - 10\n<\/pre><\/div>\n\n\n<p>Indeed, this now works! Now, we don&#8217;t need to call <code>full_id<\/code> using the parenthesis.<\/p>\n\n\n\n<p>While it is still a method, the property decorator masks that, and treats it as if it is a property of the <a href=\"https:\/\/www.askpython.com\/python\/oops\/python-classes-objects\" class=\"rank-math-link\">class<\/a>! Doesn&#8217;t the name make sense now!?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Using property with a setter<\/h2>\n\n\n\n<p>In the above example, the approach worked because we didn&#8217;t explicitly modify the <code>full_id<\/code> property directly. By default, using <code>@property<\/code> makes that property only read-only.<\/p>\n\n\n\n<p>This means that you can&#8217;t explicitly change the property.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\ns.full_id = &quot;Kishore&quot;\nprint(s.full_id)\n<\/pre><\/div>\n\n\n<p><strong>Output<\/strong><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n---&gt; 21 s.full_id = &quot;Kishore&quot;\n     22 print(s.full_id)\n\nAttributeError: can&#039;t set attribute\n<\/pre><\/div>\n\n\n<p>Obviously, we don&#8217;t have the permissions, since the property is read-only!<\/p>\n\n\n\n<p>To make the property writable, remember the <code>property().setter<\/code> method we talked about, which is also a decorator?<\/p>\n\n\n\n<p>Turns out we can add another <code>full_id<\/code> property using <code>@full_id.setter<\/code>, to make it writable. The <code>@full_id.setter<\/code> will inherit everything about the original <code>full_id<\/code> property, so we can add it directly!<\/p>\n\n\n\n<p>However, we cannot directly use the <code>full_id<\/code> property in our setter property. Notice that it will lead to an infinite recursion descent!<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nclass Student():\n    def __init__(self, name, id):\n        self.name = name\n        self.id = id\n\n    def get_name(self):\n        return self.name\n\n    @property\n    def full_id(self):\n        return self.name + &quot; - &quot; + str(self.id)\n\n    @full_id.setter\n    def full_id(self, value):\n        # Infinite recursion depth!\n        # Notice that you&#039;re calling the setter property of full_id() again and again\n        self.full_id = value\n<\/pre><\/div>\n\n\n<p>To avoid this, we&#8217;ll be adding a hidden attribute <code>_full_id<\/code> to our class. We&#8217;ll modify the <code>@property<\/code> decorator to return this attribute instead.<\/p>\n\n\n\n<p>The updated code will now look like this:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\nclass Student():\n    def __init__(self, name, id):\n        self.name = name\n        self.id = id\n        self._full_id = self.name + &quot; - &quot; + str(self.id)\n\n    def get_name(self):\n        return self.name\n\n    @property\n    def full_id(self):\n        return self._full_id\n\n    @full_id.setter\n    def full_id(self, value):\n        self._full_id = value\n\ns = Student(&quot;Amit&quot;, 10)\nprint(s.name)\nprint(s.full_id)\n\ns.name = &quot;Rahul&quot;\nprint(s.name)\nprint(s.full_id)\n\ns.full_id = &quot;Kishore - 20&quot;\nprint(s.name)\nprint(s.id)\nprint(s.full_id)\n<\/pre><\/div>\n\n\n<p><strong>Output<\/strong><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nAmit\nAmit - 10\nRahul\nAmit - 10\nRahul\n10\nKishore - 20\n<\/pre><\/div>\n\n\n<p>We&#8217;ve successfully made the <code>full_id<\/code> property have getter and setter attributes!<\/p>\n\n\n\n<hr class=\"wp-block-separator has-text-color has-background has-vivid-green-cyan-background-color has-vivid-green-cyan-color\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>Hopefully, this gave you a better understanding of the property decorator, and also why you may need to use class attributes, like <code>_full_id<\/code>.<\/p>\n\n\n\n<p>These hidden class attributes (like <code>_full_id<\/code>) make it really easy for us to use the outer <code>full_id<\/code> properties!<\/p>\n\n\n\n<p>This is exactly why properties are <em>heavily<\/em> used in modern open-source projects.<\/p>\n\n\n\n<p>They make it extremely easy for the end-user, and also make it easy for the developers to segregate hidden attributes from non-hidden properties!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">References<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/stackoverflow.com\/questions\/17330160\/how-does-the-property-decorator-work-in-python\" class=\"rank-math-link\" target=\"_blank\" rel=\"noopener\">StackOverflow Question<\/a> on Property Decorators<\/li><\/ul>\n\n\n\n<hr class=\"wp-block-separator has-text-color has-background has-vivid-green-cyan-background-color has-vivid-green-cyan-color\"\/>\n","protected":false},"excerpt":{"rendered":"<p>Hello again! In this article, we&#8217;ll be taking a look at Python property decorator. Python has a very useful feature called decorators, which is just a syntactic sugar for function-wrappers. Here, we&#8217;ll be focusing on the property decorator, which is a special type of decorator. This topic may be a bit confusing to you, so [&hellip;]<\/p>\n","protected":false},"author":7,"featured_media":6222,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[],"class_list":["post-6181","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-built-in-methods"],"blocksy_meta":[],"_links":{"self":[{"href":"https:\/\/www.askpython.com\/wp-json\/wp\/v2\/posts\/6181","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.askpython.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.askpython.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.askpython.com\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/www.askpython.com\/wp-json\/wp\/v2\/comments?post=6181"}],"version-history":[{"count":0,"href":"https:\/\/www.askpython.com\/wp-json\/wp\/v2\/posts\/6181\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.askpython.com\/wp-json\/wp\/v2\/media\/6222"}],"wp:attachment":[{"href":"https:\/\/www.askpython.com\/wp-json\/wp\/v2\/media?parent=6181"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.askpython.com\/wp-json\/wp\/v2\/categories?post=6181"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.askpython.com\/wp-json\/wp\/v2\/tags?post=6181"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}