Click to Visit Homepage : zzyzz.top


The related functions and attributes for managing attributes - 操作属性的重要属性和函数

  1 特性 property 都是类属性(静态变量),但是特性管理的其实是实例属性的存取,
  2         ****** 回顾 -'类方法' classmethod 和 '静态方法' staticmethod 皆可以访问类的静态变量(类变量),但不能访问实例变量(即类方法中定义的变量)
  3         
  4         示例1 - 实例属性'覆盖'同名类属性(attribute);但不会'覆盖'同名的类特性(property),
  5             class C(object):
  6                 c = 'It is class\'s attribute'
  7             
  8                 @property
  9                 def pc(self):
 10                     return 'It is property pc'
 11             
 12             if __name__ == "__main__":
 13                 print(C.pc)
 14                 tester = C()
 15                 print(tester.__class__)              #Conclusion
 16                 print(vars(tester.__class__))        #Conclusion
 17                 print(vars(tester))                  #1
 18                 print(C.c)                           #2
 19                 print(tester.c)                      #2
 20                 tester.c = '12345'                   #3
 21                 print(vars(tester))                  #3
 22                 print(tester.c)                      #3
 23                 print(C.c)                           #3
 24             
 25                 print('=====================')
 26                 print(vars(tester))              
 27                 print(C.pc)                          #4
 28                 print(tester.pc)                     #5
 29                 tester.pc = '333333'                 #6
 30                 tester.__dict__['pc'] = '22222'      #7 直接创建实例的同名属性 - pc, 通过 tester.__dict__ 属性
 31                 print(vars(tester))
 32                 print(C.pc)
 33                 print(tester.pc)
 34                 print(getattr(tester,'pc','notfound'))
 35                 print(tester.__dict__['pc'])
 36             
 37             Output,
 38                                                  # 实例属性'覆盖'同名类属性
 39                  <property object at 0x035B9840>
 40                  
 41                  <class '__main__.C'>
 42                 {'__module__': '__main__', 'c': "It is class's attribute", 'pc': <property object at 0x01DA9840>, 
 43                 '__dict__': <attribute '__dict__' of 'C' objects>, 
 44                 '__weakref__': <attribute '__weakref__' of 'C' objects>, '__doc__': None}      #Conclusion                                                           
 45                 
 46                 {}                                   #1 实例 tester 属性
 47                 It is class's attribute              #2
 48                 It is class's attribute              #2 tester.c 获取的是属性 C.c
 49                 {'c': '12345'}                       #3 创建同名实例属性 c
 50                 12345                                #3
 51                 It is class's attribute              #3
 52                                                  # 同名实例属性不会'覆盖' 类特性 property 
 53                 =====================
 54                 {'c': '12345'}
 55                 <property object at 0x035B9840>      #4 类的 property object
 56                 It is property pc                    #5 实例读取 property pc 
 57                 
 58                 tester.pc = '333333'                 #6 因为同名实例属性不会'覆盖' 类特性 property, 故 raise error 'AttributeError: can't set attribute'  
 59                     AttributeError: can't set attribute  #6, 即 实例中的 property pc 是 '只读' 属性.
 60                     
 61                 {'c': '12345', 'pc': '22222'}         #7
 62                 <property object at 0x035B9840>
 63                 It is property pc
 64                 It is property pc
 65                 22222
 66             
 67             Conclusion,
 68                 tester.c 这样的表达式不是从 tester 实例开始寻找属性 c ,而是从 tester.__class__ 开始找,
 69                 仅当类中没有同名为 c 的特性时, Python 才会在 tester 实例 __dict__ 属性中寻找.
 70                 这条规则不仅适用于特性,还适用于一整类描述符——覆盖型描述符(overriding descriptor).
 71                 其实,特性 property 其实是覆盖描述符 overriding descriptor.
 72             
 73     相关的特殊属性,
 74     
 75         __class__
 76             对象所属类的引用(即 obj.__class__ 与 type(obj) 的作用相同), 
 77             
 78         __dict__
 79             一个'字典'形式的映射,存储对象或类的可写属性.
 80__dict__ 属性的对象,任何时候都能随意设置新属性.
 81             如果类有 __slots__ 属性,它的实例可能没有 __dict__ 属性.
 82             参见下面对 __slots__ 属性的说明.
 83             
 84         __slots__
 85             一个类中可能定义该这属性,作用是限制实例能有哪些属性.
 86             __slots__ 属性的值是一个字符串组成的元组,指明允许有的属性(如('x', 'y')).
 87             如果 __slots__ 中没有 '__dict__',那么该类的实例则没有 __dict__ 属性,
 88             实例只允许有指定名称的属性。
 89             __slots__ 属性的值虽然可以是一个列表,但是最好始终使用元组,
 90             因为处理完类的定义体之后再修改 __slots__ 列表没有任何作用,所以使用可变的序列容易让人误解。
 91     
 92     相关的内置函数,
 93     
 94         dir([object])
 95             列出对象的大多数属性(https://docs.python.org/3/library/functions.html#dir),
 96             dir 函数的目的是交互式使用,因此没有提供完整的属性列表,只列出一组“重要的”属性名.
 97             dir 函数能审查有或者没有 __dict__ 属性的对象. 
 98             dir 函数不会列出 __dict__ 属性本身,但会列出其中(__dict__ 中)元素的键. 
 99             dir 函数也不会列出以下几个特殊属性, __mro__, __bases__, __name__.
100             如果没有指定 object 参数, dir 函数会列出当前作用域中的名称.
101         
102         vars([object])
103             返回 object 对象的 __dict__ 属性; 如果实例所属的类定义了 __slots__ 属性,
104             实例没有 __dict__ 属性,那么 vars 函数不能处理那个实例(dir 函数能处理这样的实例).
105             如果没有指定参数,那么 vars() 函数的作用与 locals() 函数一样:返回表示本地作用域的字典.
106             
107         getattr(object, name[, default])
108             从 object 对象中获取 name 字符串对应的属性,获取的属性可能来自对象所属的类或超类.
109             如果没有指定的属性, getattr 函数抛出 AttributeError 异常,或者返回 default 参数的值.
110         
111         hasattr(object, name)
112             如果 object 对象中存在指定的属性,或者能以某种方式(例如继承)通过 object 对象获取指定的属性,返回 True.
113             (https://docs.python.org/3/library/functions.html#hasattr)
114             这个函数的实现方法是调用 getattr(object, name) 函数,看看是否抛出 AttributeError 异常.
115         
116         setattr(object, name, value)
117             把 object 对象指定属性的值设为 value,前提是 object 对象能接受那个值.
118             这个函数可能会创建一个新属性,或者覆盖现有的属性.
119                        
120     相关的特殊方法,
121         在用户自己定义的类中,下述特殊方法分别用于获取、设置、删除和列出属性,
122         
123         使用点号(obj.attr)或内置的 getattr、 hasattr 和 setattr 函数存取属性都会触发下述列表中相应的特殊方法.
124         但是,直接通过实例的 __dict__ 属性读写属性不会触发这些特殊方法(果需要,通常会使用这种方式跳过特殊方法).
125         (https://docs.python.org/3/reference/datamodel.html#special-method-lookup)中说道:
126             对用户自己定义的类来说,如果隐式调用特殊方法,仅当特殊方法在对象所属的类型上定义,而不是在对象的实例字典中定义时,
127             才能确保调用成功.
128             ****** 也就是说,要假定特殊方法从类上获取,即便操作目标是实例也是如此.因此.特殊方法不会被同名实例属性遮盖.
129         
130         以下论述中,假设类名为 Class, obj 是 Class 类的实例, attr 是 obj 的属性.
131         不论是使用点号(obj.attr)存取属性,还是使用前面所述的某个'内置函数'都会触发下述某个特殊方法.
132             如, obj.attr 和 getattr(obj, 'attr', 123) 会触发 Class.__getattribute__(obj, 'attr') 方法.
133             
134             __delattr__(self, name)
135                 只要使用 del 语句删除属性,就会调用这个方法。如, del obj.attr 会调用 Class.__delattr__(obj, 'attr') 方法.
136                 
137             __dir__(self)
138               把对象传给 dir 函数时调用,列出属性. 例如, dir(obj) 触发 Class.__dir__(obj) 特殊方法.
139             
140             __getattr__(self, name)
141                 仅当获取指定的属性失败, 搜索过 obj, Class 和超类之后调用. 表达式 obj.no_such_attr, getattr(obj, 'no_such_attr'),
142                 hasattr(obj, 'no_such_attr') 可能会触发 Class.__getattr__(obj, 'no_such_attr') 特殊方法.
143                 但是,仅当在 obj, Class 和超类中找不到指定的属性时才会触发.
144                 
145             __getattribute__(self, name)
146                 尝试获取指定的属性时总会调用这个方法,不过,寻找的属性是特殊属性或特殊方法时除外. 
147                 点号与 getattr 和 hasattr 内置函数会触发这个方法.调用 __getattribute__ 方法且抛出 AttributeError 异常时,
148                 才会调用 __getattr__ 特殊方法. 为了在获取 obj 实例的属性时不导致无限递归, 
149                 __getattribute__ 方法的实现要使用 super().__getattribute__(obj, name).
150                 
151             __setattr__(self, name, value)
152                 尝试设置指定的属性时总会调用这个方法.点号(obj.attr)和 setattr 内置函数会触发这个方法.
153                 比如, obj.attr = 123 和 setattr(obj, 'attr', 123) 都会触发 Class.__setattr__(obj, ‘attr’, 123) 特殊方法的调用.
154              
155             其实, 特殊方法 __getattribute____setattr__ 不管怎样都会调用, 几乎会影响每一次属性存取,
156             因此比 __getattr__ 方法(只处理不存在的属性名)更难正确使用.
157 结论, 与其自己定义这些特殊方法,不如使用特性或描述符相对不易出错.

 

posted @ 2017-09-25 18:07  zzYzz  阅读(166)  评论(0)    收藏  举报


Click to Visit Homepage : zzyzz.top