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     ‘‘‘
时间: 2024-10-13 07:22:52

python描述符、property、函数(类)装饰器实例解析的相关文章

python 基础篇 11 函数进阶----装饰器

11. 前??能-装饰器初识本节主要内容:1. 函数名的运?, 第?类对象2. 闭包3. 装饰器初识 一:函数名的运用: 函数名是一个变量,但他是一个特殊变量,加上括号可以执行函数. ?. 闭包什么是闭包? 闭包就是内层函数, 对外层函数(非全局)的变量的引?. 叫闭包 可以使用_clesure_检测函数是否是闭包  返回cell则是闭包,返回None则不是 闭包的好处: 由它我们可以引出闭包的好处. 由于我们在外界可以访问内部函数. 那这个时候内部函数访问的时间和时机就不?定了, 因为在外部,

Python基础(7)闭包函数、装饰器

一.闭包函数 闭包函数:1.函数内部定义函数,成为内部函数, 2.改内部函数包含对外部作用域,而不是对全局作用域名字的引用 那么该内部函数成为闭包函数 #最简单的无参闭包函数 def func1() name='ares' def func2() print(name) #有参和返回值的闭包函数 def timmer(func): def wrapper(*args,**kwargs): start_time = time.time() res=func(*args,**kwargs) stop

Python(72)_生成器函数与装饰器复习

1  装饰器复习,注意打印的顺序 #-*-coding:utf-8-*- import os import time ''' 语法糖 ''' def wrapper(f): # 装饰器函数 ,f是被装饰的函数 def inner(*args,**kwargs): # 定义了内部函数,一定和return inner对应 ''' 在被装饰函数执行前要做的事情''' print('在被装饰函数执行前要做的事情') ret = f(*args,**kwargs) # 这句话是真正函数的执行 ''' 在被

Python之路(十二):描述符,类装饰器,元类

python基础之面向对象(描述符.类装饰器及元类) 描述符 描述符(__get__,__set__,__delete__)   # 这里着重描述了python的底层实现原理 1. 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议. __get__():调用一个属性时,触发 __set__():为一个属性赋值时,触发 __delete__():采用del删除属性时,触发 1 class

python 描述符 上下文管理协议 类装饰器 property metaclass

1.描述符 #!/usr/bin/python env # coding=utf-8 # 数据描述符__get__ __set__ __delete__ ''' 描述符总结 描述符是可以实现大部分python类特性中的底层魔法,包括@classmethod,@staticmethd,@property甚至是__slots__属性 描述符是很多高级库和框架的重要工具之一,描述符通常是使用到装饰器或者元类的大型框架中的一个组件 注意事项: 一 描述符本身应该定义成新式类,被代理的类也应该是新式类 二

19 描述符应用 与类的装饰器

上下文管理协议 class Open: def __init__(self,name): self.name = name def __enter__(self): print('执行enter') def __exit__(self, exc_type, exc_val, exc_tb): print('执行exit') with Open('a.txt') as f: print(f) print('______') print('00000') with open 执行了enter f为e

python函数、装饰器、迭代器、生成器

5月21日,请假结婚,然后性格惰性来了,不怎么想看视频和笔记,性格中的弱点开始出现,开始做的不错,渐渐开始松懈,直至放弃--- 函数补充进阶 函数对象 函数的嵌套 名称空间与作用域 闭包函数 函数之装饰器 函数之迭代器 函数之生成器 内置函数 一.函数补充进阶 1.函数对象:  函数是第一类对象,即函数可以当作数据传递,它的应用形式也被称为高阶函数,函数的特性如下: a. 可以被引用 1 # def foo(): 2 # print('from foo') 3 # 4 # func = foo

property内置装饰器函数和@name.setter、@name.deleter

# property # 内置装饰器函数 只在面向对象中使用 # 装饰后效果:将类的方法伪装成属性 # 被property装饰后的方法,不能带除了self外的任何参数 from math import pi class Circle: def __init__(self, r): self.r = r def perimeter(self): return 2 * pi * self.r def area(self): return pi * self.r**2 * pi c1 = Circle

python day4笔记 常用内置函数与装饰器

1.常用的python函数 abs             求绝对值 all               判断迭代器中所有的数据是否为真或者可迭代数据为空,返回真,否则返回假 any             判断迭代器中的数据是否有一个为真,有返回真,可迭代数据为空或者没有真,返回假 bin             转换整数为二进制字符串 hex            转换整数为十六进制字符串 oct             转换整数为八进制字符串 bool           转换数据为布尔值