Marcos Gonzalez
Marcos Gonzalez

Reputation: 1096

Properties with and without sugar

Please don't laugh. I am desperate.

Here is a canonical example of a python class with a getter and a setter (from Wikipedia):

class Student(object):
    # Initializer
    def __init__(self, name):
        # An instance variable to hold the student's name
        self._name = name

    # Getter method
    @property
    def name(self):
        return self._name

    # Setter method
    @name.setter
    def name(self, new_name):
        self._name = new_name

Now my version without decorators:

class Student(object):
    # Initializer
    def __init__(self, name):
        # An instance variable to hold the student's name
        self._name = name

    # Getter method
    def name(self):
        return self._name
    name=property(fget=name)

    # Setter method
    def set_name(self, new_name):
        self._name = new_name
    name = property(fset=set_name)

... except that the second version just does not work. If we instatiate the Student class, e.g. Bob=Student('Bob'), Bob.name throws AttributeError:unreadable attribute.

I promise I will donate 100 points as soon as my reputation reaches 10k to the kind soul that stoops to pointing out the bug before the downvotes start pouring in.

Upvotes: 1

Views: 504

Answers (2)

Martijn Pieters
Martijn Pieters

Reputation: 1123400

You need to name the getter too:

name = property(fget=name, fset=set_name)

or simply

name = property(name, set_name)

See the property documentation.

The @ decorator syntax is simply syntactic sugar; the following form:

@decorator_expression
def function_name(...):
    ...

is executed as:

def function_name(...):
    ...
function_name = decorator_expression(function_name)

Note how the decorator_expression part is treated as a callable with the function being passed in as the first argument. A property() is no different in that respect.

After the first property is defined for name, you have a new object name in your class namespace, the property object. That object has a .setter() method, which just returns the property with the setter replaced by the new function passed in.

Thus, the syntax @name.setter results in the .setter() method on the existing property instance being called, and that method returns a property with it's setter being replaced.

So, you could also spell your explicit property creator thus:

name = property(name)
name = name.setter(set_name)

Your version simply replaced the name property (defined with a getter) with one defining only a setter, the two having no relation otherwise.

Upvotes: 5

TehTris
TehTris

Reputation: 3217

getters and setters are kinda pointless in python, unless they are actually doing things.

class kid:
    def __init__(self,name):
        self.name = name


>>>bill = kid('bill')
>>>bill.name = 'johnny' #is good enough
>>>bill.name
johnny
>>>bill.job = 'student'
>>>bill.job
student

Upvotes: 0

Related Questions