????????这里,我将与您分享一些令人惊叹的 Python 装饰器,它们可以将您的代码减少一半。听起来好得令人难以置信,对吧?好吧,让我向您展示它们是如何工作的以及为什么应该在项目中使用它们。
????????Python 装饰器是一个强大的功能,允许您修改函数或类的行为而不更改其源代码。它们本质上是接受另一个函数作为参数并返回一个包装原始函数的新函数的函数。这样,您可以在不修改原始函数的情况下添加一些额外的功能或逻辑。
????????例如,假设您有一个将消息打印到控制台的函数:
def hello():
print("Hello, world!")
????????现在,假设您想要测量执行此函数需要多长时间。您可以编写另一个函数,使用该time
模块计算执行时间,然后调用原始函数:
import time
def measure_time(func):
def wrapper():
start = time.time()
func()
end = time.time()
print(f"Execution time: {end - start} seconds")
return wrapper
????????请注意,该measure_time
函数返回另一个名为 的函数wrapper
,它是原始函数的修改版本。该wrapper
函数做了两件事:记录执行的开始和结束时间,并调用原始函数。
????????现在,要使用此功能,您可以执行以下操作:
hello = measure_time(hello)
hello()
????????这会输出类似这样的内容:
<span style="background-color:#f9f9f9"><span style="color:#242424">你好世界!
执行时间:0.000123456789秒</span></span>
????????正如您所看到的,我们已经成功地向该hello
函数添加了一些额外的功能,而无需更改其代码。然而,有一种更优雅、更简洁的方法可以使用装饰器来完成此操作。装饰器只是语法糖,允许您使用@
符号将一个函数应用到另一个函数。例如,我们可以像这样重写之前的代码:
Hello, world!
Execution time: 0.000123456789 seconds
????????这将产生与以前相同的输出,但代码要少得多。该@measure_time
行相当于说hello = measure_time(hello)
,但它看起来更干净且更具可读性。
????????Python 装饰器的用途有很多,例如:
????????Python 中有很多内置的装饰器,例如@staticmethod
、@classmethod
、@property
、@functools.lru_cache
、@functools.singledispatch
等。您还可以出于各种目的创建自己的自定义装饰器。以下是 Python 装饰器的一些示例,可以将代码减少一半:
@timer
装饰器????????这个装饰器与我们之前看到的装饰器类似@measure_time
,但它可以应用于任何接受任意数量参数并返回任意值的函数。它还使用functools.wraps
装饰器来保留原始函数的名称和文档字符串。这是代码:
import time
from functools import wraps
def timer(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"Execution time of {func.__name__}: {end - start} seconds")
return result
return wrapper
????????现在,您可以使用此装饰器来测量任何函数的执行时间,例如:
@timer
def factorial(n):
"""Returns the factorial of n"""
if n == 0 or n == 1:
return 1
else:
return n * factorial(n - 1)
@timer
def fibonacci(n):
"""Returns the nth Fibonacci number"""
if n == 0 or n == 1:
return n
else:
return fibonacci(n - 1) + fibonacci(n - 2)
print(factorial(10))
print(fibonacci(10))
????????这会输出类似这样的内容:
Execution time of factorial: 1.1920928955078125e-06 seconds
3628800
Execution time of fibonacci: 0.000123456789 seconds
55
@debug
装饰器????????该装饰器对于调试目的很有用,因为它打印它所包装的函数的名称、参数和返回值。它还使用functools.wraps
装饰器来保留原始函数的名称和文档字符串。这是代码:
from functools import wraps
def debug(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with args: {args} and kwargs: {kwargs}")
result = func(*args, **kwargs)
print(f"{func.__name__} returned: {result}")
return result
return wrapper
现在,您可以使用此装饰器来调试任何函数,例如:
@debug
def add(x, y):
"""Returns the sum of x and y"""
return x + y
@debug
def greet(name, message="Hello"):
"""Returns a greeting message with the name"""
return f"{message}, {name}!"
print(add(2, 3))
print(greet("Alice"))
print(greet("Bob", message="Hi"))
这会输出类似这样的内容:
Calling add with args: (2, 3) and kwargs: {}
add returned: 5
5
Calling greet with args: ('Alice',) and kwargs: {}
greet returned: Hello, Alice!
Hello, Alice!
Calling greet with args: ('Bob',) and kwargs: {'message': 'Hi'}
greet returned: Hi, Bob!
Hi, Bob!
@memoize
装饰器????????该装饰器对于优化递归或昂贵函数的性能很有用,因为它会缓存先前调用的结果,并在再次传递相同的参数时返回它们。它还使用functools.wraps
装饰器来保留原始函数的名称和文档字符串。这是代码:
from functools import wraps
def memoize(func):
cache = {}
@wraps(func)
def wrapper(*args):
if args in cache:
return cache[args]
else:
result = func(*args)
cache[args] = result
return result
return wrapper
????????现在,您可以使用此装饰器来记忆任何函数,例如:
@memoize
def factorial(n):
"""Returns the factorial of n"""
if n == 0 or n == 1:
return 1
else:
return n * factorial(n - 1)
@memoize
def fibonacci(n):
"""Returns the nth Fibonacci number"""
if n == 0 or n == 1:
return n
else:
return fibonacci(n - 1) + fibonacci(n - 2)
print(factorial(10))
print(fibonacci(10))
????????这将输出与以前相同的结果,但执行时间要快得多,因为结果会被缓存和重用。
????????Python 装饰器是一种强大而优雅的方法,可以在不更改源代码的情况下修改函数或类的行为。它们可以帮助您将代码减少一半、提高代码可读性、重用代码、分离您的关注点以及扩展现有代码的功能。我希望您喜欢这篇博文并学到一些新东西。如果您有任何问题或意见,请随时在下面留下。不要忘记与可能有兴趣了解有关 Python 装饰器的更多信息的朋友和同事分享这篇文章。谢谢阅读!