zoukankan      html  css  js  c++  java
  • 关于property的一些记录,以及描述符(descriptor)中__get__,__set__,__delete__的属性使用。

    首先先介绍一下property的类,因为需要深入了解property就随便了解了下描述符,property实现就用了这个功能。

    property以前在我脑子里面就是方法转属性的装饰圈,现在回想虽然也对,但只不过是里面功能的冰山一角。

    首先介绍property的用法,后面上代码:

    In [11]: class Rectange: 
        ...:     def __init__(self): 
        ...:         self.width = 0 
        ...:         self.height = 0 
        ...:  
        ...:     def set_size(self, size): 
        ...:         self.width, self.height = size 
        ...:  
        ...:     def get_size(self): 
        ...:         return self.width, self.height 
        ...:  
        ...:     def del_size(self): 
        ...:         del self.width,self.height 
        ...:  
        ...:     size = property(get_size, set_size, del_size) 
        ...:                                                                                                         
    
    In [12]: r = Rectange()                                                                                          
    
    In [13]: r.size                                                                                                  
    Out[13]: (0, 0)
    
    In [14]: r.size = 5,5                                                                                            
    
    In [15]: r.size                                                                                                  
    Out[15]: (5, 5)
    
    In [16]: r.height                                                                                                
    Out[16]: 5
    
    In [17]: del r.size                                                                                              
    
    In [18]: r.size                                                                                                  
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-18-f01c9e7af2ea> in <module>
    ----> 1 r.size
    
    <ipython-input-11-6b0a6fffb0c4> in get_size(self)
          8 
          9     def get_size(self):
    ---> 10         return self.width, self.height
         11 
         12     def del_size(self):
    
    AttributeError: 'Rectange' object has no attribute 'width'
    
    In [19]: r.height                                                                                                
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-19-9fec4be02cd3> in <module>
    ----> 1 r.height
    
    AttributeError: 'Rectange' object has no attribute 'height'
    

    根据实际操作,size已变成了property的实例,调用size可以对多属性进行查询,复制,删除,使用起来非常的方便。

    property后面后面共有四个关键字参数,fget,fset,fdel,doc,doc参数我没用过,官方解释是一个带文档字符串的特性。

    所以在实例化的时候必须关键词参数的顺序输入读取属性,写入属性,删除操作的顺序

    这是第二种property的使用,效果都一样,这个用的是装饰器的用法。(非常不好用)

    In [36]: class Rectange: 
        ...:     def __init__(self): 
        ...:         self.width = 0 
        ...:         self.height = 0 
        ...:  
        ...:     @property 
        ...:     def size(self): 
        ...:         return self.width, self.height 
        ...:      
        ...:     @size.setter 
        ...:     def size(self, size): 
        ...:         self.width, self.height = size 
        ...:  
        ...:      
        ...:     @size.deleter 
        ...:     def size(self): 
        ...:         del self.width,self.height 
        ...:                                                                                                         
    
    In [37]:                                                                                                         
    
    In [37]: r= Rectange()                                                                                           
    
    In [38]: r.size = 3,4                                                                                            
    
    In [39]: r.size                                                                                                  
    Out[39]: (3, 4)
    
    In [40]: del r.size                                                                                              
    
    In [41]: r.height                                                                                                
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-41-9fec4be02cd3> in <module>
    ----> 1 r.height
    
    AttributeError: 'Rectange' object has no attribute 'height'
    

     为什么不好用,首相你定义的方法名必须相同,经过我的测试@property必须用在读取参数身上,麻烦的是不能单独设置写入的property

    In [47]: class Rectange: 
        ...:     def __init__(self): 
        ...:         self.width = 0 
        ...:         self.height = 0 
        ...:  
        ...:  
        ...:     def dsize(self): 
        ...:         return self.width, self.height 
        ...:  
        ...:     @property 
        ...:     def size(self, size): 
        ...:         self.width, self.height = size 
        ...:  
        ...:  
        ...:      
        ...:     def dsize(self): 
        ...:         del self.width,self.height 
        ...:                                                                                                         
    
    In [48]: r = Rectange()                                                                                          
    
    In [49]: r.size=3,4                                                                                              
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-49-08f82adabb51> in <module>
    ----> 1 r.size=3,4
    
    AttributeError: can't set attribute
    

    这个就是说,方法转函数限制条件很多,如果是读取的话,问题不大,如果是带参数写入,必须先定义一个读取,一个写入,不能单独把写入的方法改成属性复制。

    总体使用下来,强烈推荐用property的类实例话对多方法进行合并成一个对象属性进行操作。

    为什么property能够实行这个功能呢,那是因为__get__,__set__,__delete__魔方函数定义了描述符。

    概念:描述符就是将某种特殊类型的类的实例指派给另一个类的属性。

    In [56]: class MyDescriptor: 
        ...:     def __get__(self, instance, owner): 
        ...:         print('__get__output=====>', instance, owner,self) 
        ...:  
        ...:     def __set__(self, instance, value): 
        ...:         print('__set__output=====>' , instance, value) 
        ...:  
        ...:     def __delete__(self, instance): 
        ...:         print('__delete__output=====>', instance) 
        ...:  
        ...: class Test: 
        ...:     x = MyDescriptor() 
        ...:                                                                                                         
    
    In [57]: t = Test()                                                                                              
    
    In [58]: t.x                                                                                                     
    __get__output=====> <__main__.Test object at 0x10e9ca710> <class '__main__.Test'> <__main__.MyDescriptor object at 0x10de16210>
    
    In [59]: t                                                                                                       
    Out[59]: <__main__.Test at 0x10e9ca710>
    
    In [60]: t.x = 20                                                                                                
    __set__output=====> <__main__.Test object at 0x10e9ca710> 20
    
    In [61]: Test                                                                                                    
    Out[61]: __main__.Test
    

    其实从代码中可以看出来,在描述符里面任何一个参数里面都有这instance,这个instance就是用户描述符类属性实例化的对方,案例这里面就是t。

    对x的属性进行读取,复制都会在描述符对应里面的__get__,__set__函数里面都将执行。

    In [63]: class MyProperty: 
        ...:     def __init__(self, fget=None, fset=None, fdel=None): 
        ...:         self.fget = fget 
        ...:         self.fest = fset 
        ...:         self.fdel = fdel 
        ...:          
        ...:     def __get__(self, instance, owner): 
        ...:         return self.fget(instance) 
        ...:      
        ...:     def __set__(self, instance, value): 
        ...:         self.fest(instance, value) 
        ...:      
        ...:     def __delete__(self, instance): 
        ...:         self.fdel(instance) 
        ...:          
        ...: class Demo: 
        ...:     def __init__(self): 
        ...:         self.vv = None 
        ...:      
        ...:     def getvv(self): 
        ...:         return self.vv 
        ...:      
        ...:     def setvv(self,value): 
        ...:         self.vv = value 
        ...:      
        ...:     def delvv(self): 
        ...:         del self.vv 
        ...:      
        ...:     cute = MyProperty(getvv, setvv, delvv) 
        ...:                                                                                                         
    
    In [64]: dd =Demo()                                                                                              
    
    In [65]: dd.cute = 5                                                                                             
    
    In [66]: dd.cute                                                                                                 
    Out[66]: 5
    
    In [67]: del dd.cute                                                                                             
    
    In [68]: dd.cute                                                                                                 
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-68-b9d4fbd43102> in <module>
    ----> 1 dd.cute
    
    <ipython-input-63-86b6cb623d25> in __get__(self, instance, owner)
          6 
          7     def __get__(self, instance, owner):
    ----> 8         return self.fget(instance)
          9 
         10     def __set__(self, instance, value):
    
    <ipython-input-63-86b6cb623d25> in getvv(self)
         19 
         20     def getvv(self):
    ---> 21         return self.vv
         22 
         23     def setvv(self,value):
    
    AttributeError: 'Demo' object has no attribute 'vv'

    上面的代码展示了自己编写property的效果,跟官方的比较像了,上面定义了property针对不同的操作进行的操作返回不同的操作,property里面拥有需要操作的实例与传入的方法,所以定义具体的操作非常方便。

    为了强化学习,我从一本书中抄写了一串代码强化记忆。

    In [76]: class Celsius: 
        ...:     def __init__(self, value = 26): 
        ...:         self.value = float(value) 
        ...:  
        ...:     def __get__(self, instance, owner): 
        ...:         return self.value 
        ...:  
        ...:     def __set__(self, instance, value): 
        ...:         self.value = float(value) 
        ...:  
        ...: class Fahrenheri: 
        ...:     def __get__(self, instance, owner): 
        ...:         return instance.cel * 1.8 + 32 
        ...:  
        ...:     def __set__(self, instance, value): 
        ...:         instance.cel = (float(value) -32) /1.8     # 设置华氏度温度后,返回给实例复制cel,执行Celsius的s
        ...: et功能,并复制更新。 
        ...:                                                                                                         
    
    In [77]: class Temperatrye: 
        ...:     cel = Celsius() 
        ...:     fah = Fahrenheri() 
        ...:                                                                                                         
    
    In [78]: temp = Temperatrye()                                                                                    
    
    In [79]: temp.cel                                                                                                
    Out[79]: 26.0
    
    In [80]: temp.fah                                                                                                
    Out[80]: 78.80000000000001
    
    In [81]: temp.fah = 250                                                                                          
    
    In [82]: temp.cel                                                                                                
    Out[82]: 121.11111111111111
    

     上面代码通过两个描述符对属性进行不同的切换,我觉的还是很有意思的。记号下。

    补充一些Python学习笔记中的描述符定义:

    class Descriptor:
        
        # 这个比__init__好用,都是在初始化的时候执行
        # 这个能获取到调用的类owner信息,已经类属性名name
        def __set_name__(self, owner, name):
            print(f'name: {owner.__name__}.{name}')
            self.name = f'__{name}__'
    
        def __get__(self, instance, owner):
            print(f'get: {instance}, {owner}')
            return getattr(instance, self.name, None)
        
        # setattr与.取值的效果一样,都会激活父类的__setattr__
        def __set__(self, instance, value):
            print(f'set {instance}, {value}')
            setattr(instance, self.name, value)
        
        def __delete__(self, instance):
            print(f'del: {instance}')
            raise AttributeError('Delete is disabled')
    
  • 相关阅读:
    关于动画的各种实现方法【转】
    关于弹出框的理念【转】
    jquery点击目标DIV以外关闭效果
    唯美诗句
    mouseover和this的巧用
    基于html5 canvas 的强大图表插件【Chart.js】
    关于百度地图API (持续跟新)
    JS的异步回调函数
    MMU内存管理单元(看书笔记)
    系统移植详细步骤
  • 原文地址:https://www.cnblogs.com/sidianok/p/11794961.html
Copyright © 2011-2022 走看看