zoukankan      html  css  js  c++  java
  • 昨天看了一篇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__方法,通过访问该方法的对象(类或实例)的不同,来返回不同的结果。

    能力有限,时间有限,不能写出里面具体的实现过程,只能了解到这里先。

  • 相关阅读:
    Weak Event模型
    Dispatcher Queue性能分析
    WPF中ControlTemplate,ItemsPanelTemplate ,DataTemplate
    事件与委托
    DataGrid: 数据项更新并保持多选
    【C#学习笔记】using 三种使用方式
    Python快捷键
    比特率和波特率
    c#winform程序退出的方法
    C#socket通信-----多线程
  • 原文地址:https://www.cnblogs.com/sidianok/p/11971517.html
Copyright © 2011-2022 走看看