Preserving Signatures of Decorated Functions
Decorators are a powerful tool for enhancing the functionality of Python functions. However, they can sometimes obscure the original function's signature. This can be problematic for documentation, debugging, and automated tools.
Problem:
Consider a generic decorator that converts all arguments to integers:
<code class="python">def args_as_ints(f): def g(*args, **kwargs): args = [int(x) for x in args] kwargs = dict((k, int(v)) for k, v in kwargs.items()) return f(*args, **kwargs) return g</code>
While the decoration works as expected, the decorated function's signature is replaced with "args, *kwargs", losing information about the original arguments.
Workarounds:
Several workarounds exist, but none are fully satisfactory:
Solution:
decorator module offers an elegant solution:
<code class="python">import decorator @decorator.decorator def args_as_ints(f, *args, **kwargs): args = [int(x) for x in args] kwargs = dict((k, int(v)) for k, v in kwargs.items()) return f(*args, **kwargs)</code>
This decorator preserves the original function's signature by passing it as arguments to the wrapped function.
Improved Decorator:
<code class="python">@args_as_ints def funny_function(x, y, z=3): """Computes x*y + 2*z""" return x*y + 2*z</code>
Now, the decorated function funny_function retains its original signature:
>>> help(funny_function) Help on function funny_function in module __main__: funny_function(x, y, z=3) Computes x*y + 2*z
Python 3.4+:
For Python 3.4 and above, functools.wraps provides a similar solution:
<code class="python">import functools def args_as_ints(func): @functools.wraps(func) def wrapper(*args, **kwargs): args = [int(x) for x in args] kwargs = dict((k, int(v)) for k, v in kwargs.items()) return func(*args, **kwargs) return wrapper</code>
By using these techniques, decorators can enhance function functionality while preserving their original signatures, ensuring clarity and consistency in the codebase.
以上是在 Python 中使用裝飾器時如何保留函數簽名?的詳細內容。更多資訊請關注PHP中文網其他相關文章!