Shmn
Shmn

Reputation: 703

Python Getters, Setters

class P:

    def __init__(self,x):
        self.x = x

    @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

I am trying to learn 'getters' and 'setters' methods. When I create an instance with these inputs:

p1 = P(1001) 
print(p1.x)
p1.x = -12
print(p1.x)

I get as outputs:

1001
-12

I don't know why do I get 1001 and -12 instead of 1000 and 0.

Upvotes: 1

Views: 102

Answers (1)

Daniel Pryden
Daniel Pryden

Reputation: 60997

Your real problem is that you're using Python 2.x with old-style classes. Your code as shown will work as you expect on Python 3.x (except for the broken indentation, of course). It will also work on Python 2.x if you make P a new-style class by explicitly inheriting from object (e.g. declare it as class P(object):).

In an old-style class, the problem is that your setter and getter methods are both named x, and both are competing for entries in the same namespace.

When you have code like:

@x.setter
def x(self, x):
    ...

What happens is that a new function object (confusingly, named x) is created with the code you specify, then x.setter(x_function_object) is called, and whatever x.setter returns (which will be a descriptor object with __get__ and __set__ defined) is assigned to x in the namespace dictionary that is passed to the metaclass's __new__ method and used to build the class's type.

However, in an old-style class, when you write self.x = ... then it will invoke __setattr__ directly rather than using the descriptor protocol (self.__dict__['x'].__set__(x, ...)). Thus the assignment to self.x in your __init__ method will overwrite the setter method instead of calling it.

Upvotes: 8

Related Questions