告诉你python装饰器的来龙去脉

作用: python装饰器的作用在于让程序在没有任何代码变动的情况下可以额外添加功能,使得程序更加简洁。有了装饰器,就可以抽离出与函数功能本身无关的雷同代码并继续重用
原来python装饰器就是这么回事

def say_hello():
    print("hello!")

def say_goodbye()print("goodbye!")

if __name__ == "__main__":
    say_hello() #hello!
    say_goodbye()#goodbye!

现在有以上两个程序,但是现在要在此基础上增加一些功能:在函数print之前要打印出函数得名字。
方案1:

def say_hello():
    print("say_hello function")
    print("hello!")

def say_goodbye()print("say_goodbye function")
    print("goodbye!")

if __name__ == "__main__":
    say_hello() #hello!
    say_goodbye()#goodbye!

这样子的方法,嗯嗯额,太low了
方案2:

def debug():
    import inspect
    caller_name = inspect.stack() [1][3]
    print("{} function".format(caller_name))

def say_hello():
    debug()
    print("hello!")

def say_goodbye():
    debug()
    print("goodbye!")

if __name__ == "__main__":
    say_hello()
    say_goodbye()

方案2 每个函数都要调用一下一下debug(), 有点难受!
怎么办呢?这时候python 装饰器就派上用场了。我们可以这么写

def debug(func):
    def wrapper():
        print("{} function".format(func.__name__))
        return func()
    return wrapper #返回包装过的函数

def say_hello():
    print("hello!")

def say_goodbye():
    print("goodbye!")

sayhello=debug(say_hello)
saygoodbye=debug(say_goodbye)
if __name__ == "__main__":
    sayhello()
    saygoodbye()

debug就是一个装饰器,对原函数func进行了包装,并且不用修改原函数就可以添加需要的功能,当然,我们有更加优雅的写法

def debug(func):
    def wrapper():
        print("{} function".format(func.__name__))
        return func()
    return wrapper #返回包装过的函数

@debug
def say_hello():
    print("hello!")

@debug
def say_goodbye():
    print("goodbye!")

if __name__ == "__main__":
    say_hello()
    say_goodbye()

@debug等价于func=debug(func)

被装饰函数带有参数:debug()接受一个需要装饰的函数,wrapper接受该函数的参数

def debug(func):
    def wrapper(a):
        print("{} function".format(func.__name__))
        return func(a)
    return wrapper #返回包装过的函数

@debug
def say_hello(a):
    print(a)
    print("hello!")

@debug
def say_goodbye(a):
    print(a)
    print("goodbye!")

if __name__ == "__main__":
    a=1
    say_hello(a)
    say_goodbye(a)

输出结果

say_hello function
1
hello!
say_goodbye function
1
goodbye!

带有参数的装饰器:如果我们除了输出logging的内容外,还有输出level内容,怎么办?可以这样写。装饰器接受其参数,wrapper接受被装饰的函数,inner_wrapper()接受被装饰函数的参数。

def logging(level):
    def wrapper(func):
        def inner_wrapper(a):
            print("{level}:{func} function".format(level = level,func=func.__name__))
            return func(a)
        return inner_wrapper
    return wrapper
    
@logging('info')
def say_hello(a):
    print(a)
    print("hello!")
    
@logging('info') #相当于 saygoodbye = logging('info')(say_goodbye)
def say_goodbye(a):
    print(a)
    print("goodbye!")

if __name__ == "__main__":
    a=1
    say_hello(a)
    say_goodbye(a)

output:

info:say_hello function
1
hello!
info:say_goodbye function
1
goodbye!

基于类实现的装饰器:装饰器需要接收一个callable对象,然后返回一个callable对象,在python中,callable对象一般是函数,但是如果某个对象重载了__call__() 函数,那么那个对象就是callable的。

class Test():
    def __call__(self):
        print("call me!")
 
 t=Test()
 t()  #call me! 

对于一个用类实现的装饰器,可以用__init__()接受一个函数,用__calll__()返回一个函数

class logging(object):
    def __init__(self,func):
        self.func=func
    def __call__(self,*args,**kwargs):
        print("{func} function".format(func=self.func.__name__))
        return self.func(*args,**kwargs)

@logging
def say_hello(a):
    print(a)
    print("hello!")

@logging
def say_goodbye(a):
    print(a)
    print("goodbye!")

带有参数的类实现的装饰器:在构造函数中接受的不是一个函数,而是一个参数,在__call__()中,接受一个被装饰的函数并返回一个函数。wrapper则接受被装饰函数的参数。

class logging(object):
    def __init__(self,level):
        self.level=level
    def __call__(self,func): #接受函数
        def wrapper(*args,**kwargs):
            print("{level}:{func} function".format(level=self.level, func=func.__name__))
            return func(*args,**kwargs)
        return wrapper #返回函数

@logging('info')
def say_hello(a):
    print(a)
    print("hello!")

@logging('info')
def say_goodbye(a):
    print(a)
    print("goodbye!")

内置装饰器@property:调用类方法就好像引用类属性一样,但是返回的不是函数,而是类对象。

class Test(object):
    def __init__(self,name):
        self.name=name

  
    def index(self):
        print("hello my name is %s" %self.name)

if __name__ == "__main__":
    cls = Test("file")
    print(cls.name)
    cls.index()

以上的代码可以使用内置装饰器@property,如下

class Test(object):
    def __init__(self,name):
        self.name=name

    @property
    def index(self):
        print("hello my name is %s" %self.name)

if __name__ == "__main__":
    cls = Test("file")
    print(cls.name)
    cls.index  # 相当于cls.index()

内置装饰器@staticmethod: 不用实例化就可以调用类的方法,直接类名.方法或者类名.属性。不需要self和cls参数

class Test(object):

    @staticmethod
    def index():
        print("hello my name is a")
        
if __name__ == "__main__":
    Test().index()
    Test.index()

内置装饰器@classmethod: 不用实例化就可以调用类的方法,直接类名.方法或者类名.属性。需要cls参数

class Test(object):

    @classmethod
    def index(cls):
        print("hello my name is a")
        
if __name__ == "__main__":
    Test().index()
    Test.index()

本人学渣,如有不恰当的地方,欢迎指出!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值