0

I'm learning about encapsulation and abstraction in python and i came across the property function and decorator. The common example is something like this.

class Celsius():
    def __init__(self, temperature = 0):
        self.set_temperature(temperature)

    def to_fahrenheit(self):
        return (self._temperature * 1.8) + 32

    def get_temperature(self):
        print("Getting value")
        return self._temperature

    def set_temperature(self, value):
        if value < -273:
            raise ValueError("Temperature below -273 is not possible")
        print("Setting value")
        self._temperature = value

    temperature = property(get_temperature,set_temperature)

I dont understand why the property function is assigning the descriptor to temperature and not self.temperature. Isn't it suppouse to create a getter or setter functionality to a Instance, not to the class?

something like

self.temperature = property(get_temperature,set_temperature)

using

test = Celsius()
pprint(test.__dict__)

returns that the instance object just have the self._temperature attribute (Which we are trying to make private). using pprint(Celsius.__dict__) returns that is actually the class that have the temperature attribute that we are accessing when using the objects, which to my understanding doesn't make sense since i am interested in creating functionality to the instance and access the instance atributes, not the class attributes.

Thanks in advance :)

  • 1
    There's no `self` outside the method. This is defining a class attribute. – Barmar Mar 07 '22 at 18:02
  • The function is defined for all instances of the class. – Peter Wood Mar 07 '22 at 18:04
  • But why is the syntax like that. Isnt should be assigning the property to a instance variable? – Daniel Florez Cortes Mar 07 '22 at 18:04
  • It's because you're defining the template (method) at a class level. "Every instance of this class should use these methods". At runtime they'll be executed on an instance, but when you're defining the class there's no concept of instance yet, as mentioned above – aaossa Mar 07 '22 at 18:08
  • Because `property` is a descriptor, and the descriptor protocol won't work if `property` were an instance variable – juanpa.arrivillaga Mar 07 '22 at 18:34
  • @DanielFlorezCortes no, it absolutely **should not** be assigning the `property` to an instance variable. *why* do you think that *should* be the case? – juanpa.arrivillaga Mar 07 '22 at 18:35
  • @juanpa.arrivillaga, sorry, i thoght that it should be in the instance namespace because i was reading about abstraction in other programming languages, and the articles were talking about only instance variables, so i thoght the same about python. – Daniel Florez Cortes Mar 07 '22 at 19:37

2 Answers2

0

There's no self outside the method. This is defining a class attribute.

@Barmar has a helpful comment above.

The commonly used class function parameters self and cls are not available outside of class functions. In this case, you are defining a static member of the class. It is implied by default that vars (like your temperature =) defined this way are static members of the class.

See some useful tips on static members here: Are static class variables possible in Python?

But why is the syntax like that. Isnt should be assigning the property to a instance variable?

Note the below. The behavior of class_static_var = 4 is similar to how someone may view cls.class_static_var = 4, however it is not similar to self.instance_var = 4. To define a instance var, you can use the __init__ method

class DemoClass:
    def __init__(self): 
        self.instance_var = 3
    class_static_var = 4
acegene
  • 133
  • 1
  • 6
0

You don't explain why you believe the descriptor has to be in the instance namespace, but looking at the documentation:

A descriptor is what we call any object that defines __get__(), __set__(), or __delete__(). ... Descriptors only work when used as class variables. When put in instances, they have no effect.

So, for property to work at all, it must be a member of the class, not the instance.

If you have a descriptor, Descriptor, and a class Foo:

class Foo:
    bar = Descriptor()

foo = Foo()

then the descriptor protocol will be invoked on either

Foo.bar

or

foo.bar

In any case, this is a good thing. There's no need for each instance to carry around a reference to the descriptor. Just like a method, it will belong to the class but instances have access to it.

juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
  • It was my fault, sorry, i didnt read the documentation, i only was reading articles about abstraction and they said that all instance variables should be private, so i assumed that property should work on instance variables. – Daniel Florez Cortes Mar 07 '22 at 19:39
  • @DanielFlorezCortes that's actually *not true* for python *because* you can use descriptors to control access. Almost always, you just want regular attributes, `self.foo = value` – juanpa.arrivillaga Mar 07 '22 at 19:41