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函数(类)装饰器实例解析的主要内容,如果未能解决你的问题,请参考以下文章