Nat Riddle
Nat Riddle

Reputation: 1002

Python @property vs @property.getter

I'm writing a Python class, and it I'm using the @property decorator to create properties for the class.

I haven't found much in the documentation about this decorator, but from what I can gather from Stack Overflow and the instructions in my Python linter: in its entirety, a property created with the property decorator can take on the form definition, getter, setter, deleter, as shown here:

@property
def name(self):
    return self.__name

@name.getter
def name(self):
    return self.__name

@name.setter
def name(self, value):
    self.__name=value

@name.deleter
def name(self):
    del self.__name

I'm not entirely sure what the very first block is for. The code inside it is the exact same as the getter function.

What is the first block for; how is it different from the getter block, and if it is not, can I remove either one of them?

Upvotes: 11

Views: 3490

Answers (1)

eternal_student
eternal_student

Reputation: 716

You code works the same, because the code for @name.getter is the same as the code for @property.

@property is necessary, because it defines the property.

If you try:

class MyClass:
    @name.getter
    def name(self):
        return self.__name

You will get error message:

Traceback (most recent call last):
  File "/path/to/my/code/prop.py", line 1, in <module>
    class MyClass:
  File "/path/to/my/code/prop.py", line 3, in MyClass
    @name.getter
NameError: name 'name' is not defined

So, when creating a property, you always start with:

@property
def name(self):
    return self.__name

This creates the property name and also the getter for this property, which you can see here:

class MyClass:
    @property
    def name(self):
        return self.__name

print(MyClass.name)    # Note: we didn't create any objects
print(MyClass.name.getter)

The output will be:

<property object at 0x10beee050>
<built-in method getter of property object at 0x10beee050>

If you add getter, this will overwrite the original getter.

In your case, both getters were the same, so there was no changes. But try changing the code, making the new getter different:

class MyClass:
    @property
    def name(self):  # property and original getter
        print('This one will never get called')
        return self.__name 

    @name.getter
    def name(self):  # redefined getter
        return 'hello '+self.__name

Now the class has a new getter, and if you create an object obj and then use obj.name, the new getter will be called, and not the original one.

Upvotes: 17

Related Questions