Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confusion about __get__ and __call__ in python [duplicate]

Tags:

python

See the simple example below:

class Celsius(object):
    def __init__(self, value=0.0):
        self.value = float(value)
    def __get__(self, instance, owner): 
         return self.value 
    def __set__(self, instance, value):
         self.value = float(value)
    def __call__(self):
         print('__call__ called')

class Temperature(object):
    celsius = Celsius()
    def __init__(self):
       self.celsius1 = Celsius()


T = Temperature()
print('T.celsius:', T.celsius)
print('T.celsius1:', T.celsius1)

output
T.celsius: 0.0
T.celsius1: <__main__.Celsius object at 0x023544F0>

I wonder why they have different output. I know T.celsius will call the __get__ and T.celsius1 call the __call__.

like image 572
codest Avatar asked Mar 28 '12 10:03

codest


People also ask

What is __ get __ in Python?

__get__(self, obj, type=None) : This attribute is called when you want to retrieve the information (value = obj. attr) , and whatever it returns is what will be given to the code that requested the attribute's value. gfg.

What is __ call __ method in Python?

The __call__ method enables Python programmers to write classes where the instances behave like functions and can be called like a function. When the instance is called as a function; if this method is defined, x(arg1, arg2, ...) is a shorthand for x. __call__(arg1, arg2, ...) .

What is descriptors in Python?

Descriptors are usually used to implement the underlying functions of the object system, including bound and unbound methods, class methods, and static method characteristics. In Python, it is allowed to host a class attribute to a class, and this attribute is a descriptor.


2 Answers

The differences lie in the fact the the first attribute is a class attribute while the second is an instance attribute.

As per the documentation, If an object that implements at least the first of the Descriptor methods (__get__, __set__ and __delete__) is held in a class attribute, its __get__ method will be called when accessed. This is not the case with an instance attribute. You can learn more from the howto.

The __call__ method of an object only comes into play when the object is invoked like a function:

>>> class Foo:
...    def __call__(self):
...        return "Hello there!"
...
>>> f = Foo()
>>> f() 
'Hello There!'
like image 69
brice Avatar answered Nov 15 '22 04:11

brice


From the documentation:

The following methods only apply when an instance of the class containing the method (a so-called descriptor class) appears in an owner class (the descriptor must be in either the owner’s class dictionary or in the class dictionary for one of its parents).

So descriptors (ie. objects that implement __get__, __set__ or __delete__) must be members of a class, NOT an instance.

With the followinging changes:

Temperature.celsius2 = Celsius()

T = Temperature()
print('T.celsius:', T.celsius)
print('T.celsius1:', T.celsius1)
print('T.celsius2:', T.celsius2)

The output is:

T.celsius: 0.0
T.celsius1: <__main__.Celsius object at 0x7fab8c8d0fd0>
T.celsius2:, 0.0

More links:

  • Descriptor HowTo Guide.
  • Understanding __get__ and __set__ and Python descriptors
  • http://martyalchin.com/2007/nov/23/python-descriptors-part-1-of-2/
  • https://www.google.com/?q=python%20descriptors
like image 30
codeape Avatar answered Nov 15 '22 03:11

codeape