0

So I have read a lot about property keyword and I believe I have gotten the gist of it. I came across this example

class PeopleHeight:
    def __init__(self, height = 150):
        self.height = height

    def convert_to_inches(self):
        return (self.height * 0.3937)

    def get_height(self):
        print("Inside the getter method")
        return self._height

    def set_height(self, value):
        if value < 0:
            raise ValueError("Height cannot be negative")
        print("Inside the setter method")
        self._height = value

    height = property(get_height, set_height) #---->CONFUSING

and the last statement which is confusing me

 height = property(get_height, set_height)

I understand that the property statement has the signature

property(fget=None, fset=None, fdel=None, doc=None)

What I dont get is get_height and set_height. I understand that height is a class variable (not an instance variable) but what about get_height and set_height.I am thinking that above should have been

height = property(get_height, set_height)

but thats wrong syntax as there is no self.My question is why dont we get an error when we say:

property(get_height, set_height)

as there are no definitions of get_height or set_height set as class scope.

6
  • 2
    get_height and set_height are set in class scope. All functions in the class body are class-scope objects. Commented Nov 5, 2016 at 22:14
  • i thought they were instance scope because they had self as a parameter Commented Nov 5, 2016 at 22:15
  • 1
    No, only attributes you set on self are instance attributes. Methods receive the instance as the first argument, commonly named self, but that's not really a scope as Python understands it. Commented Nov 5, 2016 at 22:17
  • Not sure what I am suppose to be looking at the link you just posted Commented Nov 5, 2016 at 22:20
  • Check out the @property decorator too. Commented Nov 5, 2016 at 22:21

1 Answer 1

2

The statements in the class body are all executed when the class statement is executed, as if the they are all inside a function. This produces a set of names, that then are used to set the class attributes. See the class statement documentation:

The class’s suite is then executed in a new execution frame (see Naming and binding), using a newly created local namespace and the original global namespace. (Usually, the suite contains mostly function definitions.) When the class’s suite finishes execution, its execution frame is discarded but its local namespace is saved. [4] A class object is then created using the inheritance list for the base classes and the saved local namespace for the attribute dictionary.

Each of the def ... statements produce function objects, assigned to the function name, so get_height and set_height are both just functions, that then end up as attributes on the class. The same applies for the height = property(get_height, set_height) line; it accesses the names get_height and set_height, calls the property() callable with these as parameters and the result is assigned to the name height.

You may be confused how methods and the property object later on get access to the instance (the self argument in methods). Both functions and property objects are descriptor objects; any descriptor object that is accessed on an instance and is found on the class is automatically bound to the instance through this protocol. Also see the Descriptor HOWTO.

You can execute all those steps manually in the interpreter:

>>> def get_height(self):
...     print("Inside the getter method")
...     return self._height
...
>>> def set_height(self, value):
...     if value < 0:
...         raise ValueError("Height cannot be negative")
...     print("Inside the setter method")
...     self._height = value
...
>>> height = property(get_height, set_height)
>>> height
<property object at 0x105758188>
>>> height.fget
<function get_height at 0x10560ce18>
>>> height.fset
<function set_height at 0x10567e730>
>>> class FakeHeight:
...     _height = 42
...
>>> instance = FakeHeight()
>>> height.__get__(instance)  # descriptor access
Inside the getter method
42
>>> height.__set__(instance, 82)  # descriptor setting
Inside the setter method
>>> instance._height
82
Sign up to request clarification or add additional context in comments.

1 Comment

"You may be confused how methods and the property object later on get access to the instance (the self argument in methods)." This is exactly what is confusing me. Thanks I am going to read up on descriptor objects

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.