类装饰器
在介绍类的装饰器之前,首先介绍一下类像函数一下运行。
创建一个类之后,并创建该类的实例,如果想函数一下运行这个类的实例,则会报错。
如:
class Test:
def __init__(self):
self.a = 100
self.b = 200
test = Test()
test()
则会报错:
出现以上问题的原因是因为,像函数一样调用类的实例的时候,实际上调用的是类中__call__函数,而在以上的代码中我们并没有进行__call__函数的编写,导致错误。补充:__call__调用时都是在最后调用。
更给以上代码为:
class Test:
def __init__(self):
self.a = 100
self.b = 200
def __call__(self):
print("我是类,我像函数一样运行")
test = Test()
test()
结果为:
用于修饰类的修饰器
用于修饰类的修饰器,相当于把被修饰的类的引用传递到,修饰器中,并将该类的名称指向返回的类。
def Test(obj):
obj.testadd = "我是修饰器添加的属性"
return obj
@Test #相当于A=obj
class A:
def __init__(self):
self.a = 100
self.b = 200
def __call__(self):
print("我是类,我像函数一样运行")
a = A()
print(a.a)
print(a.b)
print(a.testadd)
输出结果为:
类作为修饰器
类作为修饰器,被修饰的函数被传递给,类修饰器的__init__函数作为参数,然后被修饰的函数被重新指向于返回的类的实例。
如:
class Test(object):
def __init__(self,func):
print("-------初始化-------")
print("func name is %s" %func.__name__)
self.__func = func #类的私有属性self.__func也指向了test1函数的内存地址。
def __call__(self, *args, **kwargs): #test1 = Test(test1) #调用类的对象。就会调用call方法。
print("------装饰器中的功能-------")
self.__func() #self.__func指向了函数test1的内存地址。这句话相当于执行test1()函数。
#使用类作为装饰器,需要重写Call方法,没有调用test1()方法的时候,执行代码得到下面的结果
# -------初始化-------
# func name is test1
@Test #相当于 test1 = Test(test1) 也相当于func指向了下面函数test1的名字, 前面的test1指向了 Test()这个对象。
# 调用test1对象的时候相当于调用类方法Test(),调用类方法必调用__call方法,调用call方法的时候,先执行 print("------装饰器中的功能-------")
#然后在执行self.__func() ,因为self.__func函数指向的是test1函数,test1()相当于执行self.__func().
def test1():
print("----test1---------")
test1() #调用test1
输出结果为:
-------初始化-------
func name is test1
------装饰器中的功能-------
----test1---------
类作为修饰器,修饰另一个类中方法的时候,此时的被修饰的方法,被指向类修饰器的实例,如果调用的时候则不会自动再给__call__函数传递被修饰的类的self实例。
如:
class Test(object):
def __init__(self,func):
print("-------初始化-------")
#print("func name is %s" %func.__name__)
self.__func = func #类的私有属性self.__func也指向了test1函数的内存地址。
def __call__(self, *args, **kwargs): #test1 = Test(test1) #调用类的对象。就会调用call方法。
print("------装饰器中的功能-------")
print('aa',self)
self.__func( *args, **kwargs) #self.__func指向了函数test1的内存地址。这句话相当于执行test1()函数。
class A:
def __init__(self):
self.a = 100
self.b = 200
@Test #相当于sayHello=Test(sayHello)
def sayHello(self):
print("Hello")
a = A()
a.sayHello()
输出结果:
修改方法,可以手动传递缺少的实例:
a.sayHello(a)
也可以再次使用修饰器,使其变为可以自动传递的方法:
class Test(object):
def __init__(self,func):
print("-------初始化-------")
#print("func name is %s" %func.__name__)
self.__func = func #类的私有属性self.__func也指向了test1函数的内存地址。
def __call__(self, *args, **kwargs): #test1 = Test(test1) #调用类的对象。就会调用call方法。
print("------装饰器中的功能-------")
print('aa',self)
self.__func( *args, **kwargs) #self.__func指向了函数test1的内存地址。这句话相当于执行test1()函数。
def wapper(func):
def inner(*args,**kwargs):
return func(*args,**kwargs)
return inner
class A:
def __init__(self):
self.a = 100
self.b = 200
@wapper
@Test
def sayHello(self):
print("Hello")
a = A()
a.sayHello()
输出结果为:
-------初始化-------
------装饰器中的功能-------
aa <__main__.Test object at 0x0000000B8A34D828>
Hello
给类的方法使用普通修饰器
给类的方法,使用普通修饰器的时候,由于类的方法自动传递实例的特性,需要多加一个参数,进行接受自动传递的实例。
def outer(obj): # 类方法装饰器
def inner(self):
print('hello inner')
obj(self)
return inner
class Zoo(object):
def __init__(self):
pass
@outer # => zoo = outer(zoo)
def zoo(self):
print('hello zoo')
zoo = Zoo()
print(zoo.zoo.__name__)
zoo.zoo()
输出结果为:
inner
hello inner
hello zoo
用于模拟对象的装饰器–类装饰器
装饰器中也可以闭包中含有类,使用方法与修饰类的修饰器的方法一致。
def outer(clss): # 类装饰器
class Inner(object):
def __init__(self):
self.clss = clss()
def __getattr__(self, attr):
return getattr(self.clss, attr)
return Inner
@outer # Zoo = outer(Zoo)
class Zoo(object):
def __init__(self):
pass
def say(self):
print('hello world!')
zoo = Zoo()
print(zoo.__class__) # <class '__main__.outer.<locals>.Inner'>
zoo.say() # hello world!
输出结果为:
<class '__main__.outer.<locals>.Inner'>
hello world!
借鉴与:
https://blog.csdn.net/qq_29767317/article/details/80799410
https://blog.csdn.net/five3/article/details/83447467