python描述符property函数(类)装饰器实例解析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python描述符property函数(类)装饰器实例解析相关的知识,希望对你有一定的参考价值。

 

  1 import sys
  2 
  3 ‘‘‘
  4 当使用实例对象访问属性时,都会调用__getattribute__内建函数
  5 __getattribute__查找属性的优先级
  6 1、类属性
  7 2、数据描述符
  8 3、实例属性
  9 4、非数据描述符
 10 5、__getattr__()
 11 
 12 #实例.属性
 13 c.x ==>type(x).__dict__[‘x‘].__get__(x,type(x))
 14 #类.属性
 15 C.x ==>X.__dict__[‘x‘].__get__(None,C)
 16 
 17 __getattribute__伪代码:
 18    __getattribute__(property) logic:
 19   #先在类(包括父类、祖先类)的__dict__属性中查找描述符
 20   descripter = find first descripter in class and bases‘s dict(property)
 21   if descripter:#如果找到属性并且是数据描述符,就直接调用该数据描述符的__get__方法并将结果返回
 22       return descripter.__get__(instance, instance.__class__)
 23   else:#如果没有找到或者不是数据描述符,就去实例的__dict__属性中查找属性,如果找到了就直接返回这个属性
 24       if value in instance.__dict__
 25           return value
 26       #程序执行到这里,说明没有数据描述符和实例属性,则在类(父类、祖先类)的__dict__属性中查找非数据描述符
 27       value = find first value in class and bases‘s dict(property)
 28       if value is a function:#如果找到了并且这个属性是一个函数,就返回绑定后的函数
 29          return bounded function(value)
 30       else:#否则就直接返回这个属性
 31          return value
 32  #程序执行到这里说明没有找到该属性,引发异常,__getattr__函数会被调用
 33  raise AttributeNotFundedException
 34 
 35 __setattr__伪代码:
 36  __setattr__(property, value)logic:
 37  #先在类(包括父类、祖先类)的__dict__属性中查找描述符
 38  descripter = find first descripter in class and bases‘s dict(property)
 39  if descripter:#如果找到了且是数据描述符,就调用描述符的__set__方法
 40      descripter.__set__(instance, value)
 41  else:#否则就是给实例属性赋值
 42      instance.__dict__[property] = value
 43 ‘‘‘
 44 #带参数函数装饰器
 45 def log(header,footer):#相当于在无参装饰器外套一层参数
 46     def log_to_return(fun):#这里接受被装饰的函数
 47         def return_fun(*args,**kargs):
 48             print(header)
 49             fun(*args,**kargs)
 50             print(footer)
 51         return return_fun
 52     return log_to_return
 53 
 54 #带参数类型装饰器
 55 def flyable(message):
 56     def flyable_to_return(cls):
 57         def fly(self):
 58             print(message)
 59         cls.fly = fly #类属性也可以动态修改
 60         return cls
 61     return flyable_to_return
 62 
 63 #say(meaasge) ==> log(parms)(say)(message)
 64 @log(日志输出开始,结束日志输出)
 65 def say(message):
 66     print(message)
 67 
 68 #定义一个非数据描述符
 69 class myStaticObject(object):
 70     def __init__(self,fun):
 71         self.fun = fun
 72     def __get__(self,instance,owner):
 73         print(call myStaticObject __get__)
 74         return self.fun
 75 #无参的函数装饰器,返回的是非数据描述符对象
 76 def my_static_method(fun):
 77     return myStaticObject(fun)
 78 #定义一个非数据描述符
 79 class myClassObject(object):
 80     def __init__(self,fun):
 81         self.fun = fun
 82     def __get__(self,instance,owner):
 83         print(call myClassObject __get__)
 84         def class_method(*args,**kargs):
 85             return self.fun(owner,*args,**kargs)
 86         return class_method
 87 #无参的函数装饰器,返回的是非数据描述符对象
 88 def my_class_method(fun):
 89     return myClassObject(fun)
 90 
 91 #非数据描述符
 92 class des1(object):
 93     def __init__(self,name=None):
 94         self.__name = name
 95     def __get__(self,obj,typ=None):
 96         print(call des1.__get__)
 97         return self.__name
 98 #数据描述符
 99 class des2(object):
100     def __init__(self,name=None):
101         self.__name = name
102     def __get__(self,obj,typ=None):
103         print(call des2.__get__)
104         return self.__name
105     def __set__(self,obj,val):
106         print(call des2.__set__,val is %s % (val))
107         self.__name = val
108 #测试类
109 @flyable("这是一个测试类")
110 class test(object):
111     def __init__(self,name=test,age=0,sex=man):
112         self.__name = name
113         self.__age = age
114         self.__sex = sex
115 #---------------------覆盖默认的内建方法
116     def __getattribute__(self, name):
117         print("start call __getattribute__")
118         return  super(test, self).__getattribute__(name)
119     def __setattr__(self, name, value):
120         print("before __setattr__")
121         super(test, self).__setattr__(name, value)
122         print("after __setattr__")
123     def __getattr__(self,attr):
124         print("start call __getattr__")
125         return attr
126         #此处可以使用getattr()内建函数对包装对象进行授权    
127     def __str__(self):
128         return str(name is %s,age is %d,sex is %s % (self.__name,self.__age,self.__sex))
129     __repr__ = __str__ 
130 #-----------------------
131     d1 = des1(chenyang)     #非数据描述符,可以被实例属性覆盖
132     d2 = des2(pengmingyao)  #数据描述符,不能被实例属性覆盖
133     def d3(self):             #普通函数,为了验证函数(包括函数、静态/类方法)都是非数据描述符,可悲实例属性覆盖
134         print(i am a function)
135 #------------------------
136     def get_name(self):
137         print(call test.get_name)
138         return self.__name
139     def set_name(self,val):
140         print(call test.set_name)
141         self.__name = val
142     name_proxy = property(get_name,set_name)#数据描述符,不能被实例属性覆盖,property本身就是一个描述符类
143 
144     def get_age(self):       
145         print(call test.get_age)
146         return self.__age
147     age_proxy = property(get_age) #非数据描述符,但是也不能被实例属性覆盖
148 #----------------------
149     @property 
150     def sex_proxy(self):
151         print("call get sex")
152         return self.__sex
153     @sex_proxy.setter  #如果没有setter装饰,那么sex_proxy也是只读的,实例属性也无法覆盖,同property
154     def sex_proxy(self,val):
155         print("call set sex")
156         self.__sex = val
157 #---------------------
158     @my_static_method #相当于my_static_fun = my_static_method(my_static_fun)  就是非数据描述符
159     def my_static_fun():
160         print(my_static_fun)
161     @my_class_method
162     def my_class_fun(cls):
163         print(my_class_fun)
164 #end
165 
166 if __name__ == "__main__":
167     say("函数装饰器测试")
168     ‘‘‘
169     日志输出开始
170     函数装饰器测试
171     结束日志输出
172     ‘‘‘
173     t=test( )  #创建测试类的实例对象
174     ‘‘‘
175     before __setattr__
176     after __setattr__
177     before __setattr__
178     after __setattr__
179     before __setattr__
180     after __setattr__
181     ‘‘‘
182     print(str(t)) #验证__str__内建函数
183     ‘‘‘
184     start call __getattribute__
185     start call __getattribute__
186     start call __getattribute__
187     name is test,age is 0,sex is man
188     ‘‘‘
189     print(repr(t))#验证__repr__内建函数
190     ‘‘‘
191     start call __getattribute__
192     start call __getattribute__
193     start call __getattribute__
194     name is test,age is 0,sex is man
195     ‘‘‘
196     t.fly()       #验证类装饰器
197     ‘‘‘
198     start call __getattribute__
199     这是一个测试类
200     ‘‘‘
201     t.my_static_fun()#验证自定义静态方法
202     ‘‘‘
203     start call __getattribute__
204     call myStaticObject __get__
205     my_static_fun
206     ‘‘‘
207     t.my_class_fun()#验证自定义类方法
208     ‘‘‘
209     start call __getattribute__
210     call myClassObject __get__
211     my_class_fun
212     ‘‘‘
213     #以下为属性获取
214     t.d1
215     ‘‘‘
216     start call __getattribute__
217     call des1.__get__
218     ‘‘‘
219     t.d2
220     ‘‘‘
221     start call __getattribute__
222     call des2.__get__
223     ‘‘‘
224     t.d3()
225     ‘‘‘
226     start call __getattribute__
227     i am a function
228     ‘‘‘
229     t.name_proxy
230     ‘‘‘
231     start call __getattribute__
232     call test.get_name
233     start call __getattribute__
234     ‘‘‘
235     t.age_proxy
236     ‘‘‘
237     start call __getattribute__
238     call test.get_age
239     start call __getattribute__
240     ‘‘‘
241     t.sex_proxy
242     ‘‘‘
243     start call __getattribute__
244     call get sex
245     start call __getattribute__
246     ‘‘‘
247     t.xyz #测试访问不存在的属性,会调用__getattr__
248     ‘‘‘
249     start call __getattribute__
250     start call __getattr__
251     ‘‘‘
252     #测试属性写
253     t.d1 = 3  #由于类属性d1是非数据描述符,因此这里将动态产生实例属性d1
254     ‘‘‘
255     before __setattr__
256     after __setattr__
257     ‘‘‘
258     t.d1      #由于实例属性的优先级比非数据描述符优先级高,因此此处访问的是实例属性
259     ‘‘‘
260     start call __getattribute__
261     ‘‘‘
262     t.d2 = modefied
263     ‘‘‘
264     before __setattr__
265     call des2.__set__,val is modefied
266     after __setattr__
267     ‘‘‘
268     t.d2
269     ‘‘‘
270     start call __getattribute__
271     call des2.__get__
272     ‘‘‘
273     t.d3 = not a function
274     ‘‘‘
275     before __setattr__
276     after __setattr__
277     ‘‘‘
278     t.d3
279     ‘‘‘
280     start call __getattribute__
281     ‘‘‘
282     t.name_proxy = modified
283     ‘‘‘
284     before __setattr__
285     call test.set_name
286     before __setattr__
287     after __setattr__
288     after __setattr__
289     ‘‘‘
290     t.sex_proxy = women
291     ‘‘‘
292     before __setattr__
293     call set sex
294     before __setattr__
295     after __setattr__
296     after __setattr__
297     ‘‘‘
298     t.age_proxy = 3
299     ‘‘‘
300     before __setattr__
301     Traceback (most recent call last):
302       File "test.py", line 191, in <module>
303        t.age_proxy = 3
304       File "test.py", line 121, in __setattr__
305        super(test, self).__setattr__(name, value)
306     AttributeError: can‘t set attribute
307     ‘‘‘

 

以上是关于python描述符property函数(类)装饰器实例解析的主要内容,如果未能解决你的问题,请参考以下文章

python 装饰器和property

Python装饰器之 property()

Python装饰器之 property()

Python之路:描述符,类装饰器,元类

在python中嵌套描述符/装饰器

在类中装饰 @property.setter 装饰器 [重复]