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__
.
__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.
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, ...) .
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.
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!'
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:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With