python修饰器

本文介绍了Python修饰器的概念和作用,修饰器是一个能在不修改原有函数代码的基础上,为其添加额外功能的函数。常见应用场景包括日志记录、性能测试、事务处理等。修饰器通过高阶函数实现,使用@注解的形式方便地应用到目标函数上,为代码的复用和维护提供了便利。

修饰器的概念和作用

什么是修饰器

修饰器又叫装饰器,本身也是一个函数,是在原有的函数或者是方法上增添一些额外的功能。

修饰器的作用

概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

比如说这个函数是注册的功能,但有时候这个用户在执行这个操作的时候,他是已注册的用户,我这个函数已经写好了,不想动它了,那么我们就可以通过修饰器来给这个函数增加一个登录的功能。

它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。从需求谈起

引入

现在,假设我们有一个函数

def foo():  
    print('in foo()')
foo() 

为了检查这个函数的复杂度(在网络编程中程序的延时还是很重要的),需要测算运算时间,增加了计算时间的功能有了下面的代码:

import time  
def foo():  
    start = time.clock()  
    print('in foo()') 
    end = time.clock()  
    print('in foo()')
   
foo()  

这里只是写了一个函数,如果我想测量多个函数的延时,由于必须知道start与end,所以必须写在程序的开头与结尾,难道每一个程序都这样复制粘贴么?固然可行,但是,我们可以通过设计模式中将功能与数据部分分离一样,将这个测量时间的函数分离出去,就像C++中我们可以将这个测量时间的函数变为一个类,通过调用这个类,赋予不同的函数来测量不同的函数的运行时长。在python中,由于函数实际上就是对象,所以可以利用类似的方法实现:

import time  
   
def foo():  
    print('in foo()')
   
def timeit(func):  
    start = time.clock()  
    func()  
    end =time.clock()  
    print('Time Elapsed:', end - start)
   
timeit(foo)  

这里func()就可以指定函数了,但是如果我不想填这个函数或者这个功能函数并不能修改成类似的形式怎么办?我们需要的是最大限度的少改动:

import time  
   
def foo():  
    print('in foo()')
   
# 定义一个计时器,传入一个,并返回另一个附加了计时功能的方法  
def timeit(func):  
       
    # 定义一个内嵌的包装函数,给传入的函数加上计时功能的包装  
    def wrapper():  
        start = time.clock()  
        func()  
        end =time.clock()  
        print('Time Elapsed:', end - start) 
       
    # 将包装后的函数返回  
    return wrapper  
   
foo = timeit(foo)   #可以直接写成@timeit + foo定义,python的"语法糖"
foo()

在这个代码中,timeit(foo)不是直接产生调用效果,而是返回一个与foo参数列表一致的函数(其实是函数回调),此时此foo非彼foo!因为此时的foo具有了timeit的功效,简单来说就是能够让你在装饰前后执行代码而无须改变函数本身内容,装饰器是一个函数,而其参数为另外一个函数。

修饰器本质

对于Python的这个@注解语法糖- Syntactic Sugar 来说,当你在用某个@decorator来修饰某个函数func时,如下所示:

@decorator
def func():
    pass

其解释器会解释成下面这样的语句:

func = decorator(func)

等等…这不就是把一个函数当参数传到另一个函数中,然后再回调吗?是的,但是,我们需要注意,那里还有一个赋值语句,把decorator这个函数的返回值赋值回了原来的func。 根据《函数式编程》中的first class functions中的定义的,你可以把函数当成变量来使用,所以,decorator必需得返回了一个函数出来给func,这就是所谓的higher order function 高阶函数,不然,后面当func()调用的时候就会出错。

注意

  • 修饰器的关键字是 @ ,Python代码中只要出现了它,就可以想到是修饰器了

  • 修饰器修饰的是函数或者是方法,不能修饰一个类

  • 修饰器必须出现在被修饰函数或者方法的前一行,不能够将修饰器定义在函数的同行

个人总结

其实修饰器更像是一个函数,但修饰器将被修饰函数作为形参,先执行修饰器中的语句,再返回传递进来的函数对象(其他函数对象也行),并调用返回出来的函数

reference

谈谈python修饰器 - 简书 (jianshu.com)

Python修饰器 - whgiser - 博客园 (cnblogs.com)

退休的龙叔

### Python装饰器的使用和原理 Python装饰器是一种特殊类型的函数,它可以修改其他函数或类的行为,而无需修改它们的源代码。装饰器本质上是一个接受函数作为参数的函数,并返回一个新的函数。这种机制使得可以在不改变原有代码结构的情况下,为函数添加新的功能。 装饰器的核心原理是函数的嵌套和闭包。当使用 `@decorator` 语法时,Python 会将被装饰的函数作为参数传递给装饰器函数,并将装饰器返回的新函数替换原来的函数。例如,以下代码展示了一个简单的装饰器,在执行目标函数之前打印一条消息: ```python def decorator(func): def wrapper(): print("Executing before the function...") func() return wrapper @decorator def hello(): print("Hello, world!") hello() ``` 运行结果如下: ``` Executing before the function... Hello, world! ``` 在此示例中,`hello` 函数被 `decorator` 装饰器包裹,`hello` 实际上指向了 `wrapper` 函数,而 `wrapper` 在调用 `func()` 之前执行了额外的操作[^2]。 ### 装饰器的进阶用法 装饰器不仅可以用于简单的函数包装,还可以带参数,甚至可以装饰带有参数的函数。以下是一个能够处理任意参数的装饰器示例: ```python def decorator_with_args(arg): def decorator(func): def wrapper(*args, **kwargs): print(f"Decorator argument: {arg}") print("Executing before the function...") result = func(*args, **kwargs) print("Executing after the function...") return result return wrapper return decorator @decorator_with_args("test") def greet(name): print(f"Hello, {name}!") greet("Alice") ``` 运行结果如下: ``` Decorator argument: test Executing before the function... Hello, Alice! Executing after the function... ``` 在这个例子中,`decorator_with_args` 是一个带有参数的装饰器工厂函数,它返回一个真正的装饰器 `decorator`,而 `decorator` 返回的 `wrapper` 函数则处理了任意数量的位置参数和关键字参数[^4]。 ### 装饰器的实际应用 装饰器在实际开发中有广泛的应用场景,例如: - **权限控制**:可以使用装饰器来检查用户是否有权限执行某个操作。例如,Flask 框架中的 `@login_required` 装饰器可以限制只有登录用户才能访问某些视图函数。 - **性能测试**:可以使用装饰器来测量函数的执行时间,如下所示: ```python import time def timeit(func): def wrapper(*args, **kwargs): start_time = time.time() result = func(*args, **kwargs) end_time = time.time() print(f"Function {func.__name__} took {end_time - start_time:.4f} seconds to execute.") return result return wrapper @timeit def slow_function(): time.sleep(2) slow_function() ``` 运行结果如下: ``` Function slow_function took 2.0002 seconds to execute. ``` 此示例中的 `timeit` 装饰器可以自动记录被装饰函数的执行时间,非常适合用于性能调试[^3]。 ### 装饰器的链式调用 Python 还支持多个装饰器的链式调用。装饰器的执行顺序是从内到外,即最靠近函数的装饰器最先执行。例如: ```python def decorator1(func): def wrapper(*args, **kwargs): print("Decorator 1 before") result = func(*args, **kwargs) print("Decorator 1 after") return result return wrapper def decorator2(func): def wrapper(*args, **kwargs): print("Decorator 2 before") result = func(*args, **kwargs) print("Decorator 2 after") return result return wrapper @decorator1 @decorator2 def say_hello(): print("Hello") say_hello() ``` 运行结果如下: ``` Decorator 1 before Decorator 2 before Hello Decorator 2 after Decorator 1 after ``` 在这个例子中,`say_hello` 函数首先被 `decorator2` 装饰,然后被 `decorator1` 装饰。因此,`decorator2` 的 `wrapper` 函数会在 `decorator1` 的 `wrapper` 函数内部被调用[^1]。 ### 总结 Python 装饰器是一种强大的工具,能够以非常简洁的方式扩展函数的功能。通过理解装饰器的实现原理和使用方式,可以写出更加模块化、可重用的代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值