Python 装饰器

1. 什么是装饰器?

在 Python 中,装饰器是一个很大的主题。装饰器是一个函数或类,它允许在不修改被装饰对象源代码的情况下修改或增加其行为。简单来说,装饰器是在已有函数或类的基础上添加新的功能。

# 一个简单的装饰器示例

def my_decorator(func):

def wrapper():

print("Something is happening before the function is called.")

func()

print("Something is happening after the function is called.")

return wrapper

def say_hello():

print("Hello!")

say_hello = my_decorator(say_hello)

say_hello()

以上代码中定义了一个装饰器 my_decorator,它接受一个函数作为参数,并返回一个新的函数 wrapper。在新函数 wrapper 中,先执行了一些操作,然后再调用原函数 func,最后又执行了一些操作。使用装饰器改造原函数 say_hello 的方法是通过 @ 符号应用装饰器来实现的,如下所示:

@my_decorator

def say_hello():

print("Hello!")

这里的 @my_decorator 等价于 say_hello = my_decorator(say_hello),即将 say_hello 函数通过 my_decorator 装饰器重新赋值给了 say_hello。这种方式也称为语法糖。

2. 装饰器的应用

2.1 计时器示例

装饰器常用的应用场景是计时器,可以用来测试函数的性能。

import time

def timer(func):

def wrapper(*args, **kwargs):

start_time = time.time()

result = func(*args, **kwargs)

end_time = time.time()

print("Function %s took %f seconds to execute." % (func.__name__, end_time - start_time))

return result

return wrapper

@timer

def countdown(n):

while n > 0:

n -= 1

countdown(1000000)

以上代码中定义了一个装饰器 timer,它接受一个函数作为参数,并返回一个新的函数 wrapper。在新函数 wrapper 中,在调用原函数 func 之前记录开始时间,并在调用后记录结束时间,然后计算执行时间并打印出来。使用装饰器实现计时器的方式为在原函数定义上方加上 @timer

2.2 授权示例

还有一个很实用的应用场景是授权,比如在用户登录系统时检查是否有权限执行某些操作。

def login_required(func):

def wrapper(user, *args, **kwargs):

if user.is_authenticated:

return func(user, *args, **kwargs)

else:

raise Exception("Access denied.")

return wrapper

@login_required

def delete_account(user, account_id):

print("Deleting account %d for user %s." % (account_id, user.username))

delete_account({"username": "john", "is_authenticated": True}, 123)

以上代码中定义了一个装饰器 login_required,它接受一个函数作为参数,并返回一个新的函数 wrapper。在新函数 wrapper 中,先检查用户是否登录,如果登录则调用原函数 func,如果未登录则抛出异常。使用装饰器实现授权的方式为在原函数定义上方加上 @login_required

3. 带参数的装饰器

装饰器可以带有参数,这使得装饰器更加灵活和通用。

def repeat(num):

def my_decorator(func):

def wrapper(*args, **kwargs):

for i in range(num):

print("Running iteration %d" % i)

result = func(*args, **kwargs)

return result

return wrapper

return my_decorator

@repeat(3)

def say_hello(name):

print("Hello %s" % name)

say_hello("John")

以上代码中定义了一个带参数的装饰器 repeat,使用方式为在定义装饰器时先传入参数,再返回一个装饰器函数 my_decorator,该函数同样接受一个函数作为参数,并返回一个新函数 wrapper。在新函数 wrapper 中使用参数 num 循环执行原函数 func

4. 装饰器的嵌套

装饰器可以嵌套使用,这意味着一个函数可以同时被多个装饰器装饰。

def make_bold(func):

def wrapper():

return "" + func() + ""

return wrapper

def make_italic(func):

def wrapper():

return "" + func() + ""

return wrapper

@make_bold

@make_italic

def say_hello():

return "Hello World!"

print(say_hello())

以上代码中定义了两个装饰器 make_boldmake_italic,两个装饰器定义方式相同,都接受一个函数作为参数,在返回新函数 wrapper 时添加相应的 HTML 标记。同时应用这两个装饰器的方式为在原函数定义上方按照从按照从内到外的顺序依次用 @ 应用装饰器。运行以上代码后,输出结果为:

Hello World!
,表示原函数 say_hello 被先后用 make_boldmake_italic 两个装饰器修饰。

5. 总结

装饰器是 Python 编程中非常重要的概念,可以用来扩展和修改原有的函数和类。装饰器可以应用于函数、类等,是一种非常灵活和通用的编程技术。

后端开发标签