昨天看了一篇super的文章,让我对函数(function)与描述符(descriptor)有了更多的认知。记录一下。
昨天看了一篇关于super的文章,对我的基础学习还是非常有帮助的,记录一些自己的想法与笔记,加深印象。
其实当我们定义一个函数的时候,如果把函数当做一个对象,其实这个对象里面也有很多方法。
In [428]: def fun():
...: pass
...:
In [429]: dir(fun)
Out[429]:
['__annotations__',
'__call__',
'__class__',
'__closure__',
'__code__',
'__defaults__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__get__',
'__getattribute__',
'__globals__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__kwdefaults__',
'__le__',
'__lt__',
'__module__',
'__name__',
'__ne__',
'__new__',
'__qualname__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__']
里面有一些简单的我知道一些比如__name__,__sizeof__,__closure__,等
但里面有一个__get__,与__call__,__call__是直接调用的,但__get__是当做描述符(descriptor)用的,其实我们在类里面定义的方法调用的都是__get__,而且里面应该有着具体的逻辑,
要不然你用类去调用该方法与你用实例去调用该方法会不一样。
In [430]: fun.__class__ Out[430]: function In [431]: fun.__class__.__class__ Out[431]: type
从上面的代码首先了解到自定义的函数是由function实例出来的,function尽然还是由type创造出来的,看来type真的很厉害,创造的所有的类里面包含了function,想想也对。
但根据《流畅的Python》书中写到,object类和type类之间的关系很独特,object是type的的实例,而type是object的子类。
这个感觉有点像鸡与蛋的故事一样,object需要type实例创建,但type类却继承object,好比type创造了一个自己的爸爸类。
接下来,我将定义一个简单的描述符,来查看一下,我们调用这个描述符到底做了什么。
In [436]: class Son:
...: def __get__(self, instacne, cls_):
...: print('__get__', instacne, cls_)
...: def __call__(self):
...: print('__call__')
...:
In [437]: class Father:
...: des = Son()
...:
In [438]: father = Father()
In [439]: father.des
__get__ <__main__.Father object at 0x114923790> <class '__main__.Father'>
In [440]: father.des()
__get__ <__main__.Father object at 0x114923790> <class '__main__.Father'>
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-440-60c997b7a682> in <module>
----> 1 father.des()
TypeError: 'NoneType' object is not callable
In [441]: Father.des
__get__ None <class '__main__.Father'>
In [442]: Father.des()
__get__ None <class '__main__.Father'>
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-442-1e7b73a77521> in <module>
----> 1 Father.des()
TypeError: 'NoneType' object is not callable
对于描述符深刻映象来至与这个实际操作,当一个具有__get__属性的对象,在它被当做某个对象的属性时,调用这个属性,会执行该对象的__get__方法。
当不用的实例调用该对象,会发生不同的效果,如果一个把这个对象当做类属性的话,它的instance与cls返回的是Father.des __get__ None <class '__main__.Father'>
但当他用这个类的实例去调用该它时,它的instance与cls返回的是__get__ <__main__.Father object at 0x114923790> <class '__main__.Father'>
所以一个描述符可以用过__get__里面获取的instance来判断调用它的对象是实例还是类。
In [443]: class Foo:
...: def func(self):
...: pass
...:
In [444]: Foo.func
Out[444]: <function __main__.Foo.func(self)>
In [445]: foo = Foo()
In [446]: foo.func
Out[446]: <bound method Foo.func of <__main__.Foo object at 0x114893110>>
上面简单的定义了一个类,类里面定义了一个函数,但定义在类里面的函数就是方法了,但很明显这个方法也好,函数也好,肯定由__get__属性。
所以这个函数func已经变成了类Foo的属性,无论是Foo去调用还是foo去调用
In [449]: Foo.func.__get__(None,A) Out[449]: <function __main__.Foo.func(self)> In [450]: Foo.func.__get__(foo,A) Out[450]: <bound method Foo.func of <__main__.Foo object at 0x114893110>>
前面那个例子可以看出来,假如当做方法当做类属性的时候,instance是none,如果当时实例属性的时候,instance是实例本身
所以Foo.fun就好比Foo.func.__get__(None,A)
foo.fun就好比Foo.func.__get__(foo,A)
__get__函数里面通过instance的判断,返回不同的方法给对象,所以才会由前面不同的对象调用方法属性的时候,会显示绑定与未绑定的情况。
所以我们无论通过实例也好,类也好,在访问类的内部定义的方法,统统调用的是__get__方法,通过访问该方法的对象(类或实例)的不同,来返回不同的结果。
能力有限,时间有限,不能写出里面具体的实现过程,只能了解到这里先。
浙公网安备 33010602011771号