官术网_书友最值得收藏!

Making calls to objects

Key 4: All objects can be made callable.

To reuse and group code for some task, we group it in the functions classes, and then call it with different inputs. The objects that have a __call__ attribute are callable and __call__ is the entry point. For the C class, tp_call is checked in its structure:

>>> def func(): # a function
...     print("adf")
... 
>>> func()
adf
>>> func.__call__() #implicit call method
adf
>>> func.__class__.__call__(func)
adf
>>> func.__call__
<method-wrapper '__call__' of function object at 0x7ff7d9f24ea0>
>>> class C: #a callable class
...     def __call__(self):
...         print("adf")
... 
>>> c = C()
>>> c()
adf
>>> c.__call__() #implicit passing of self
adf
>>> c.__class__.__call__(c) #explicit passing of self
adf
>>> callable(lambda x:x+1)  #testing whether object is callable or not
True
>>> isinstance(lambda x:x+1, collections.Callable) #testing whether object is callable or not
True

Methods in classes are similar to functions, except that they are called with an implicit instance as a first argument. The functions are exposed as methods when they are accessed from the instance. The function is wrapped in a method class and returned. The method class stores instances in __self__ and function in __func__, and its __call__ method calls __func__ with first argument as __self__:

>>> class D:
...     pass
... 
>>> class C:
...     def do(self,):
...             print("do run",self)
... 
>>> def doo(obj):
...     print("doo run",obj)
... 
>>> c = C()
>>> d = D()
>>> doo(c)
doo run <__main__.C object at 0x7fcf543625c0>
>>> doo(d)
doo run <__main__.D object at 0x7fcf54362400>
>>> # we do not need to pass object in case of C class do method
... 
>>> c.do() #implicit pass of c object to do method
do run <__main__.C object at 0x7fcf543625c0>
>>> C.doo = doo
>>> c.doo()
doo run <__main__.C object at 0x7fcf543625c0>
>>> C.doo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: doo() missing 1 required positional argument: 'obj'
>>> C.do()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: do() missing 1 required positional argument: 'self'
>>> C.do(c)
do run <__main__.C object at 0x7fcf543625c0>
>>> C.do(d)
do run <__main__.D object at 0x7fcf54362400>
>>> c.do.__func__(d) #we called real function this way
do run <__main__.D object at 0x7fcf54362400>

Using this logic, we can also collect methods that are needed from other classes in the current class, like the following code, instead of multiple inheritances if data attributes do not clash. This will result in two dictionary lookups for an attribute search: one for instance, and one for class.

>>> #in library
... class PrintVals:
...     def __init__(self, endl):
...         self.endl = endl
...         
...     def print_D8(self, data):
...         print("{0} {1} {2}".format(data[0],data[1],self.endl))
... 
>>> class PrintKVals: #from in2 library
...     def __init__(self, knm):
...         self.knm = knm
...     
...     def print_D8(self, data):
...         print("{2}:{0} {1}".format(data[0],data[1],self.knm))
...
>>> class CollectPrint:
...     
...     def __init__(self, endl):
...         self.endl = endl
...         self.knm = "[k]"
...     
...     print_D8 = PrintVals.print_D8
...     print_D8K = PrintKVals.print_D8
... 
>>> c = CollectPrint("}")
>>> c.print_D8([1,2])
1 2 }
>>> c.print_D8K([1,2])
[k]:1 2

When we call classes, we are calling its type, that is metaclass, with class as a first argument to give us a new instance:

>>> class Meta(type):
...     def __call__(*args):
...         print("meta call",args)
... 
>>> class C(metaclass=Meta):
...     pass
... 
>>> 
>>> c = C()
meta call (<class '__main__.C'>,)
>>> c = C.__class__.__call__(C)
meta call (<class '__main__.C'>,)

Similarly, when we call instances, we are calling their type, that is class, with instance as first argument:

>>> class C:
...     def __call__(*args):
...         print("C call",args)
... 
>>> c = C()
>>> c()
C call (<__main__.C object at 0x7f5d70c2bb38>,)
>>> c.__class__.__call__(c)
C call (<__main__.C object at 0x7f5d70c2bb38>,)
主站蜘蛛池模板: 谢通门县| 博客| 蓬溪县| 囊谦县| 驻马店市| 集安市| 瓮安县| 苍南县| 江津市| 固始县| 永嘉县| 遂溪县| 石河子市| 苍南县| 铜川市| 天镇县| 永新县| 广元市| 韶关市| 贵州省| 乌苏市| 安泽县| 凌云县| 丰镇市| 巴林右旗| 永定县| 宁蒗| 河北省| 霍邱县| 荥阳市| 新沂市| 英山县| 洞口县| 高尔夫| 泰宁县| 应城市| 北流市| 南丰县| 县级市| 普宁市| 池州市|