开发者

Python装饰器代码详解

开发者 https://www.devze.com 2022-12-03 13:31 出处:网络 作者: 凡晨丹心
目录一、理解装饰器二、装饰器原型1、不带参数的装饰器2.带参数的被装饰的函数3.带参数的装饰器4.使用类作为装饰器5.使用对象作为装饰器6.多层装饰器的嵌套总结一、理解装饰器
目录
  • 一、理解装饰器
  • 二、装饰器原型
    • 1、不带参数的装饰器
    • 2.带参数的被装饰的函数
    • 3.带参数的装饰器
    • 4.使用类作为装饰器
    • 5.使用对象作为装饰器
    • 6.多层装饰器的嵌套
  • 总结

    一、理解装饰器

    所有东西都是对象(函数可以当做对象传递)

    由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。

    def function_one():
        print("测试函数")
    #可以将一个函数赋值给一个变量,比如
    foo =function_one #这里没有在使用小括号,因为我们并不是在调用function_one函数,而是在将它放在foo变量里。
    foo()
    '''
    测试函数
    Process finished with exit code 0
    '''
    

    闭包的概念:

    1)函数嵌套

    2)内部函数使用外部函数的变量

    3)外部函数的返回值为内部函数

    示例:

    def outer_function(message):
        def inner_function():
            print(message)
        return inner_function
    func = outer_function("你好")
    func() #你好
    

    二、装饰器原型

    装饰器的作用就是 不修改源代码以及原函数调用方式的情况下 给原函数增加新的功能。

    #将函数作为参数传给另一个函数
    def decorator_function(original_function):
        def wrapper_function():
        	print('wrapper executed this before {}'.format(original_function.__name__))
            original_function()
        return wrapper_function
        '''
        返回wrapper_function而不是wrapper_function();这是因为当你把一对小括号放在后面,这个函数就会执行;
        然而如果你不放括号在它后面,那它可以被到处传递,并且可以赋值给别的变量而不去执行它。
    	'''
    def display():
        print('display function ran')
    decorator_display = decorator_function(display)
    decorator_display()
    

    运行结果:

    wrapper executed this before display
    display function ran
    Process finished with exit code 0
    

    1、不带参数的装饰器

    def decorator_function(original_function):
        def wrapper_function():
            print('wrapper executed this before {}'.format(original_function.__name__))
            original_function()
        return wrapper_function
    @decorator_function
    def display():  #等价于display =decorator_function(display)
        print('display function ran')
    display()
    

    运行结果:

    wrapper executed this before display

    display function ran

    Process finished with exit code 0

    2.带参数的被装饰的函数

    def decorator_function(original_function):
        def wrapper_function(*args,**kwargs):
            print('wrapper executed this before {}'.format(original_function.__name__))
            original_function(*args,**kwargs)
        return wrapper_function
    @decorator_function
    def display():
        print('display function ran')
    @decorator_function
    def display_info(name,age):
        print('display_info ran with arguments ({},{})'.format(name,age))
    display()
    print('='*50)
    display_info('Michal',20)
    

    运行结果:

    wrapper executed this before display

    display function ran

    ==================================================

    wrapper executed this before display_info

    display_info ran with arguments (Michal,20)

    Process finished with exit code 0

    运行如下代码会出现一个问题

    def decorator_function(original_function):
        def wrapper_function(*args,**kwargs):
            print('wrapper executed this before {}'.format(original_function.__name__))
            original_function(*args,**kwargs)
        return wrapper_function
    @decorator_function
    def display():
        print('display function ran')
    @decorator_function
    def display_info(name,age):
        print('display_info ran with arg编程客栈uments ({},{})'.format(name,age))
    display_info = decorator_function(display_info)
    print(display_info.__name__)
    

    wrapper_function

    Process finished with exit code 0

    输出的应该是display_info,这里的函数被wrapper_function替代了,重写了我们函数的名字和注释文档(docstring)。python中可以使用functools.wraps来解决这个问题。

    from functools import wraps
    def decorator_function(original_function):
        @wraps(original_function)
        def wrapper_function(*args,**kwargs):
            print('wrapper executed this before {}'.format(original_function.__name__))
            original_function(*args,**kwargs)
        return wrapper_function
    @decorator_function
    def display():
        print('display function ran')
    @decorator_function
    def display_info(name,age):
        print('display_info ran with arguments ({},{})'.format(name,age))
    display_info = decorator_function(display_info)
    print(display_info.__name__)
    

    运行结果:

    display_info

    Process finished with exit code 0

    3.带参数的装饰器

    在函数中嵌入装饰器

    from functools import wraps
    def logit(logfile='out.log'):
        dehttp://www.cppcns.comf logging_decorator(func):
            @wraps(func)
            def wrapped_function(*args, **kwahttp://www.cppcns.comrgs):
                log_string = func.__name__ + " was called"
                print(log_string)
                # 打开logfile,并写入内容
                with open(logfile, 'a') as opened_file:
                    # 现在将日志打到指定的logfile
                    opened_file.write(log_string + '\n')
                return func(*args, **kwargs)
            return wrappe编程客栈d_function
        return logging_decorator
    @logit()
    def myfunc1():
        pass
    myfunc1()
    # Output: myfunc1 was called
    # 现在一个叫做 out.log 的文件出现了,里面的内容就是上面的字符串
    @logit(logfile='func2.log')
    def myfunc2():
        pass
    myfunc2()
    # Output: myfunc2 was called
    # 现在一个叫做 func2.log 的文件出现了,里面的内容就是上面的字符串
    

    4.使用类作为装饰器

    class myDecorator(object):
         def __init__(self, f):
             print("inside myDecorator.__init__()")
             f() # Prove that function definition has completed
         def __call__(self):
             print("inside myDecorator.__call__()")
     ​
     @myDecorator
     def aFunction():
         print("inside aFunction()")
     ​
     print("Finished decorating aFunction()")
     ​
     aFunction()
    

    运行结果:

    inside myDecorator.__init__()
    inside aFunction()
    Finished decorating aFunction()
    inside myDecorator.__call__()
    Process finished with exit code 0
    

    被装饰后的函数aFunction()实际上已经是类myDecorator的对象。当再调用aFunction()函数时,实际上就是调用类myDecorator的对象,因此会调用到类myDecorator的__call__()方法。

    因此使用类作为装饰器装饰函数来对函数添加一些额外的属性或功能时,一般会在类的__init__()方法中记录传入的函数,再在__call__()调用修饰的函数及其它额外处理。

    class entryExit(object):
         def __initcltbFA__(self, f):
             self.f = f
         def __call__(self):
             print("Entering", self.f.__name__)
             self.f()
             print("Exited", self.f.__name__)
     ​
     @entryExit
     def func1():
         print("inside func1()")
     ​
     @entryExit
     def func2():
         print("inside func2()")
     ​
     func1()
     func2()
    

    运行结果:

    Entering func1

    inside func1()

    Exited func1

    Entering func2

    inside func2()

    Exited func2

    Process finished with exit code 0

    5.使用对象作为装饰器

    空参:

    from functools import wraps
    class decorator_class:
        def __init__(self):
            print('执行decorator_class类的__init__()方法')
        def __call__(self, original_function):
            print('执行decorator_class类的__call__()方法')
            @wraps(original_function)
            def wrapped_function(*args, **kwargs):
                print('call method executed this before {}'.format(original_function.__name__))
                print('执行' + original_function.__name__ + '()')
                original_function(*args, **kwargs)
                print(original_function.__name__ + '()执行完毕')
            return wrapped_function
    @decorator_class()
    def display_info(name,age):
        print('display_info ran with arguments ({},{})'.format(name,age))
    display_info('Michael',20)
    

    运行结果如下:

    执行decorator_class类的__init__()方法

    执行decorator_class类的__call__()方法

    call method executed this before display_info

    执行display_info()

    display_info ran with arguments (Michael,20)

    display_info()执行完毕

    Process finished with exit code 0

    带参数:

    from functools import wraps
    class decorator_class:
        def __init__(self,arg1, arg2):
            print('执行decorator_class类的__init__()方法')
            self.arg1 =arg1
            self.arg2=arg2
        def __call__(self, original_function):
            print('执行decorator_class类的__call__()方法')
            @wraps(original_function)
            def wrapped_function(*args, **kwargs):
            	print('执行wrapped_function()')
                print('call method executed this before {}'.format(original_function.__name__))
                print('装饰器参数:', self.arg1, self.arg2)
                print('执行' + original_function.__name__ + '()')
                original_function(*args, **kwargs)
                print(original_function.__name__ + '()执行完毕')
            return wrapped_function
    @decorator_class('Hello', 'World')
    def display_info(name,age):
        print('display_info ran with arguments ({},{})'.format(name,age))
    display_info('Michael',20)
    

    运行结果如下:

    执行decorator_class类的__init__()方法

    执行decorator_class类的__call__()方法

    执行wrapped_function()

    call method executed this before display_info

    装饰器参数: Hello World

    执行display_info()

    display_info ran with arguments (Michael,20)

    display_info()执行完毕

    Process finished with exit code 0

    示例2:

    from functools import wraps
    class logit(object):
        def __init__(self, logfile='out.log'):
            self.logfile = logfile
        def __call__(self, func):
            @wraps(func)
            def wrapped_function(*args, **kwargs):
                log_string = func.__name__ + " was called"
                print(log_string)
                # 打开logfile并写入
                with open(self.logfile, 'a') as opened_file:
                    # 现在将日志打到指定的文件
                    opened_file.write(log_string + '\n')
                # 现在,发送一个通知
                self.notify()
                return func(*args, **kwargs)
            return wrapped_function
        def notify(self):
            # logit只打日志,不做别的
            pass
    @logit()
    def myfunc1():
        pass
    

    6.多层装饰器的嵌套

    #装饰器1
    def decorator1(func):
        #定义装饰之后的函数
        def wrapper1():
            # 装饰器1
            print('1-----装饰1之前')
            # 调用基本函数
            func()
            # 扩展功能2
            print('1-----装饰1之后')
        return wrapper1
    #装饰器2
    def decorator2(func):
        #定义装饰之后的函数
        def wrapper2():
            # 装饰器2
            print('2-----装饰2之前')
            # 调用基本函数
            func()
            # 扩展功能2
            print('2-----装饰2之后')
        return wrapper2
    #基本函数
    @decorator2   # 第二步:test = decorator2(eat) = test2
    @decorator1   # 第一步:test = decorator1(eat)  = test1
    def test():
        print('测试')
    #调用函数
    test()
    

    运行结果:

    2-----装饰2之前

    1-----装饰1之前

    测试

    1-----装饰1之后

    2-----装饰2之后

    Process finished with exit code 0

    总结

    本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

    0

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    关注公众号