昨天看了一篇关于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>In [440]: father.des() __get__ <__main__.Father object at 0x114923790> --------------------------------------------------------------------------- TypeError Traceback (most recent call last) in ----> 1 father.des() TypeError: 'NoneType' object is not callable In [441]: Father.des __get__ None In [442]: Father.des() __get__ None --------------------------------------------------------------------------- TypeError Traceback (most recent call last) in ----> 1 Father.des() TypeError: 'NoneType' object is not callable
对于描述符深刻映象来至与这个实际操作,当一个具有__get__属性的对象,在它被当做某个对象的属性时,调用这个属性,会执行该对象的__get__方法。
当不用的实例调用该对象,会发生不同的效果,如果一个把这个对象当做类属性的话,它的instance与cls返回的是Father.des __get__ None
但当他用这个类的实例去调用该它时,它的instance与cls返回的是__get__ <__main__.Father object at 0x114923790>
所以一个描述符可以用过__get__里面获取的instance来判断调用它的对象是实例还是类。
In [443]: class Foo: ...: def func(self): ...: pass ...: In [444]: Foo.func Out[444]:In [445]: foo = Foo() In [446]: foo.func Out[446]: >
上面简单的定义了一个类,类里面定义了一个函数,但定义在类里面的函数就是方法了,但很明显这个方法也好,函数也好,肯定由__get__属性。
所以这个函数func已经变成了类Foo的属性,无论是Foo去调用还是foo去调用
In [449]: Foo.func.__get__(None,A) Out[449]:In [450]: Foo.func.__get__(foo,A) Out[450]: >
前面那个例子可以看出来,假如当做方法当做类属性的时候,instance是none,如果当时实例属性的时候,instance是实例本身
所以Foo.fun就好比Foo.func.__get__(None,A)
foo.fun就好比Foo.func.__get__(foo,A)
__get__函数里面通过instance的判断,返回不同的方法给对象,所以才会由前面不同的对象调用方法属性的时候,会显示绑定与未绑定的情况。
所以我们无论通过实例也好,类也好,在访问类的内部定义的方法,统统调用的是__get__方法,通过访问该方法的对象(类或实例)的不同,来返回不同的结果。
能力有限,时间有限,不能写出里面具体的实现过程,只能了解到这里先。