前言:
当前你们对“python 嵌套类”可能比较注意,我们都需要知道一些“python 嵌套类”的相关文章。那么小编同时在网上汇集了一些有关“python 嵌套类””的相关资讯,希望咱们能喜欢,小伙伴们一起来了解一下吧!1 python可调用实例.嵌套函数.描述符装饰类方法
函数装饰器可以是一个普通函数,也可以是一个可调用类的实例(有__call__()方法的类,此类实例可以像调用函数一样进行小括号运算,自动调用__call__()方法,即有__call__()方法的类实例,称为可调用类的实例)。
函数装饰器可以装饰普通函数,也可以装饰类方法。
类方法被普通函数装饰时,python向self传递隐含的主体实例;
类方法被可调用类实例装饰时,python只传递这个类的实例,可通过显式传递被装饰的类实例来正确调用类方法。
1.1 可调用类实例装饰类方法
用法
>>> class CountTrace: def __init__(self,func): self.calls=0 self.func=func #实例名()运算,自动调用__call__ # 调用 payraise(0.2)自动调用 CountTrace的 __call__ # 调用 __call__() 时,第1个入参 self 为 CountTrace 类实例 # 而 payraise(self,rate)的self被给了0.2, # 而未自动传 当前调用的 StaffWithDecorator 类实例 def __call__(self,*args,**kargs): print('self=',self) print('*args=',args) self.calls+=1 print('调用{}{}次'.format(self.func.__name__,self.calls)) return self.func(*args,**kargs) >>> class StaffWithDecorator: def __init__(self,name,pay): self.name=name self.pay=pay # payraise 重新绑定为 CountTrace 类实例 # 调用 payraise()相当于调用 CountTrace的 __call__ @CountTrace def payraise(self,rate): self.pay*=(1.0+rate)
描述
可调用类实例装饰类方法时,只传可调用类实例给call()方法的self,不会自动将装饰类的实例自动传递给args,导致self.func(args,**kargs)即调用payraise(self,rate)时,self没有赋值为类StaffWithDecorator的当前实例,赋值成为了0.2,最终rate缺少rate入参。
可以通过显式的将当前实例传递给self来正确调用。
示例
>>> class CountTrace: def __init__(self,func): self.calls=0 self.func=func #实例名()运算,自动调用__call__ def __call__(self,*args,**kargs): print('self=',self) print('*args=',args) self.calls+=1 print('调用{}{}次'.format(self.func.__name__,self.calls)) return self.func(*args,**kargs) >>> @CountTrace def testsquare(x): print(x**2) >>> testsquare(3) self= <__main__.CountTrace object at 0x012634D0> *args= (3,) 调用testsquare1次 9 # 未使用装饰器,正常执行 >>> class StaffNoDecorator: def __init__(self,name,pay): self.name=name self.pay=pay def payraise(self,rate): self.pay*=(1.0+rate) >>> s1=StaffNoDecorator('张三',51000) >>> s1.payraise(.2) >>> s1.pay 61200.0 # 有使用装饰器,未传入被装饰方法的实例导致报缺少入参 rate >>> class StaffWithDecorator: def __init__(self,name,pay): self.name=name self.pay=pay @CountTrace def payraise(self,rate): self.pay*=(1.0+rate) >>> s1=StaffWithDecorator('张三',51000) >>> s1.payraise(.2) self= <__main__.CountTrace object at 0x040D9CF0> # 只传了0.2,赋值给了self,导致 rate 未传值 *args= (0.2,) 调用payraise1次 Traceback (most recent call last): File "<pyshell#35>", line 1, in <module> s1.payraise(.2) File "<pyshell#26>", line 11, in __call__ return self.func(*args,**kargs) TypeError: payraise() missing 1 required positional argument: 'rate' # 有使用装饰器,被装饰方法的self传成了0.2而非被装饰方法的类实例导致报错 >>> class StaffWithDecorator: def __init__(self,name,pay): self.name=name self.pay=pay @CountTrace def payraise(self): print('self=',self) self.pay*=(1.0+rate) >>> s1=StaffWithDecorator('张三',51000) >>> s1.payraise(.2) self= <__main__.CountTrace object at 0x01263750> *args= (0.2,) 调用payraise1次 # self传成了0.2 self= 0.2 Traceback (most recent call last): File "<pyshell#53>", line 1, in <module> s1.payraise(.2) File "<pyshell#26>", line 11, in __call__ return self.func(*args,**kargs) File "<pyshell#51>", line 8, in payraise self.pay*=(1.0+rate) AttributeError: 'float' object has no attribute 'pay'
显式传递payraise的self
>>> class CountTrace: def __init__(self,func): self.calls=0 self.func=func #实例名()运算,自动调用__call__ def __call__(self,*args,**kargs): print('self=',self) print('*args=',args) self.calls+=1 print('调用{}{}次'.format(self.func.__name__,self.calls)) return self.func(*args,**kargs) >>> class StaffWithDecorator: def __init__(self,name,pay): self.name=name self.pay=pay @CountTrace def payraise(self,rate): self.pay*=(1.0+rate) >>> s1=StaffWithDecorator('张三',51000) # 显式将s1传递给payraise()的self >>> s1.payraise(s1,0.2) self= <__main__.CountTrace object at 0x03978D50> *args= (<__main__.StaffWithDecorator object at 0x03978E10>, 0.2) 调用payraise1次 >>> s1.pay 61200.01.2 嵌套函数装饰类方法
描述
使用嵌套函数装饰器,可以装饰普通函数和类方法,并且能正常工作,不需要额外显式送类实例。
嵌套函数装饰类方法时,自动将类实例传递给类方法的self。
示例
>>> def counttrace(func): calls=0 def wrapper(*args,**kargs): print('func=',func) print('args=',args) nonlocal calls calls+=1 print('调用 {} {} 次'.format(func.__name__,calls)) return func(*args,**kargs) return wrapper >>> @counttrace def testsquare(x): print(x**2) >>> class StaffWithDecorator: def __init__(self,name,pay): self.name=name self.pay=pay # 嵌套函数装饰类方法,调用时自动将类实例传递给*args到self @counttrace def payraise(self,rate): print('self=',self) self.pay*=(1.0+rate) >>> testsquare(3) func= <function testsquare at 0x03E001E0> args= (3,) 调用 testsquare 1 次 9 >>> s1=StaffWithDecorator('张三',51000) >>> s1.payraise(0.2) func= <function StaffWithDecorator.payraise at 0x03E00390> args= (<__main__.StaffWithDecorator object at 0x0398D8D0>, 0.2) 调用 payraise 1 次 self= <__main__.StaffWithDecorator object at 0x0398D8D0> >>> s1.pay 61200.01.3 描述符装饰类方法1.3.1 get和call
描述
在之前的描述符章节学习过,描述符是一个类,它有__get__()、__set__()、__delete__()方法,并且将此类实例赋值给另一个类的属性,进行使用。
__get__()拦截属性的点号运算,__call__()拦截实例的小括号运算。
描述符同时定义call和get时,get方法需要返回一个可调用对象,比如此实例本身,否则无法进行实例的小括号运算。
get方法有三个参数:self,instance,owner。
示例
>>> class GetClass: # __get__()拦截点号.运算 # 需返回实例本身self # 才能进行小括号运算 def __get__(self,instance,owner): print('获取属性') return self # __call__()拦截小括号()运算 def __call__(self): print('可调用类实例') >>> class TestGet: gc=GetClass() >>> tg=TestGet() # 点号.运算 >>> tg.gc 获取属性 <__main__.GetClass object at 0x0097AED0> # 点号.运算 和 小括号()运算 >>> tg.gc() 获取属性 可调用类实例1.3.2 描述符装饰类方法
描述
描述符是一个有get、set、delete方法的类,并且将描述符类实例分配其他类的一个属性,会自动拦截此属性的点号、赋值、删除运算。
装饰器编写为一个描述符,被装饰的主体类方法会重新绑定为描述符类实例,进行点号运算和小括号运算时,会自动调用描述符的get和call方法。
描述符可以装饰普通函数和类方法。
(1) 装饰器定义__call__()方法;
(2) 装饰器定义__get__()方法,接收描述符类实例和主体类实例,返回可调用实例,此可调用实例的构造函数接收描述符类实例和主体类实例;
(3) 返回的可调用实例进行小括号运算时,进行描述符类实例的小括号运算,调用描述符类的call方法,将主体类实例和主体类实例原来的类方法的入参一并传递到*args。
示例
>>> class CountTrace: def __init__(self,func): self.calls=0 self.func=func #实例名()运算,自动调用__call__ def __call__(self,*args,**kargs): print('self1=',self) print('*args=',args) self.calls+=1 print('调用 {} {} 次'.format(self.func.__name__,self.calls)) return self.func(*args,**kargs) def __get__(self,instance,owner): print('self2=',self) print('instance=',instance) print('owner=',owner) # 返回可调用对象,否则无法进行小括号运算 return wrapper(self,instance) >>> class wrapper: def __init__(self,desc,subj): self.desc=desc self.subj=subj # 定义小括号运算 def __call__(self,*args,**kargs): # 实例小括号运算,desc()调用 CountTrace 的 __call__ return self.desc(self.subj,*args,**kargs) >>> @CountTrace def testsquare(x): print(x**2) >>> class StaffWithDecorator: def __init__(self,name,pay): self.name=name self.pay=pay @CountTrace def payraise(self,rate): print('self3=',self) self.pay*=(1.0+rate) >>> testsquare(3) self1= <__main__.CountTrace object at 0x0398D570> *args= (3,) 调用 testsquare 1 次 9 >>> s1=StaffWithDecorator('张三',51000) >>> s1.payraise(0.2) self2= <__main__.CountTrace object at 0x0398D7D0> instance= <__main__.StaffWithDecorator object at 0x0398DED0> owner= <class '__main__.StaffWithDecorator'> self1= <__main__.CountTrace object at 0x0398D7D0> *args= (<__main__.StaffWithDecorator object at 0x0398DED0>, 0.2) 调用 payraise 1 次 self3= <__main__.StaffWithDecorator object at 0x0398DED0>
本文首发微信公众号:梯阅线条,
更多内容参考python知识分享或软件测试开发目录。