龙空技术网

python可调用实例.嵌套函数.描述符装饰类方法

梯阅线条 64

前言:

当前你们对“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.0
1.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.0
1.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知识分享或软件测试开发目录。

标签: #python 嵌套类 #python嵌套函数里面包含类怎么运行