gpt4 book ai didi

python-2.7 - 如何将关键字参数添加到 Python 2.7 中的包装函数?

转载 作者:行者123 更新时间:2023-12-04 15:19:30 25 4
gpt4 key购买 nike

我首先要强调的是,我已经广泛地搜索了网络和 Python 文档 + StackOverflow,但没有设法找到这个问题的答案。我还要感谢任何花时间阅读本文的人。

正如标题所示,我正在用 Python 编写一个装饰器,我希望它为包装函数添加关键字参数( 请注意 :我知道如何向装饰器本身添加参数,这不是我想要的'我在问)。

这是 工作示例 我编写的一段代码完全适用于 Python 3(特别是 Python 3.5)。它使用装饰器参数,将关键字参数添加到包装函数,并定义新函数并将其添加到包装函数。

from functools import wraps

def my_decorator(decorator_arg1=None, decorator_arg2=False):
# Inside the wrapper maker

def _decorator(func):
# Do Something 1

@wraps(func)
def func_wrapper(
*args,
new_arg1=False,
new_arg2=None,
**kwds):
# Inside the wrapping function
# Calling the wrapped function
if new_arg1:
return func(*args, **kwds)
else:
# do something with new_arg2
return func(*args, **kwds)

def added_function():
print("Do Something 2")

func_wrapper.added_function = added_function
return func_wrapper

return _decorator

现在可以通过以下方式使用此装饰器:
@my_decorator(decorator_arg1=4, decorator_arg2=True)
def foo(a, b):
print("a={}, b={}".format(a,b))

def bar():
foo(a=1, b=2, new_arg1=True, new_arg2=7)
foo.added_function()

现在,虽然这适用于 Python 3.5(我假设适用于任何 3.x),但我还没有设法使其适用于 Python 2.7。我收到了 SyntaxError: invalid syntax在尝试为 func_wrapper 定义新关键字参数的第一行中,表示声明 new_arg1=False, 的行, 导入包含此代码的模块时。

将新关键字移动到 func_wrapper 的参数列表的开头解决了 SyntaxError但似乎与包装函数的签名不一致;我现在收到错误 TypeError: foo() takes exactly 2 arguments (0 given)调用 foo(1, 2)时.如果我明确分配参数,此错误就会消失,如 foo(a=1, b=2) ,但这显然还不够——不出所料,我的新关键字参数似乎“窃取”了发送到包装函数的前两个位置参数。这是 Python 3 没有发生的事情。

我很想得到你的帮助。感谢您抽出时间来阅读。

谢伊

最佳答案

要将参数添加到现有函数的签名,同时使该函数表现得像普通的 python 函数(正确的帮助、签名和 TypeError 在提供错误参数的情况下引发),您可以使用 makefun ,我专门开发它来解决这个用例。
特别是 makefun提供@wraps 的替代品有一个 new_sig指定新签名的参数。这是您的示例的编写方式:

try:  # python 3.3+
from inspect import signature, Parameter
except ImportError:
from funcsigs import signature, Parameter

from makefun import wraps, add_signature_parameters

def my_decorator(decorator_arg1=None, decorator_arg2=False):
# Inside the wrapper maker

def _decorator(func):
# (1) capture the signature of the function to wrap ...
func_sig = signature(func)
# ... and modify it to add new optional parameters 'new_arg1' and 'new_arg2'.
# (if they are optional that's where you provide their defaults)
new_arg1 = Parameter('new_arg1', kind=Parameter.POSITIONAL_OR_KEYWORD, default=False)
new_arg2 = Parameter('new_arg2', kind=Parameter.POSITIONAL_OR_KEYWORD, default=None)
new_sig = add_signature_parameters(func_sig, last=[new_arg1, new_arg2])

# (2) create a wrapper with the new signature
@wraps(func, new_sig=new_sig)
def func_wrapper(*args, **kwds):
# Inside the wrapping function

# Pop the extra args (they will always be there, no need to provide default)
new_arg1 = kwds.pop('new_arg1')
new_arg2 = kwds.pop('new_arg2')

# Calling the wrapped function
if new_arg1:
print("new_arg1 True branch; new_arg2 is {}".format(new_arg2))
return func(*args, **kwds)
else:
print("new_arg1 False branch; new_arg2 is {}".format(new_arg2))
# do something with new_arg2
return func(*args, **kwds)

# (3) add an attribute to the wrapper
def added_function():
# Do Something 2
print('added_function')

func_wrapper.added_function = added_function
return func_wrapper

return _decorator

@my_decorator(decorator_arg1=4, decorator_arg2=True)
def foo(a, b):
"""This is my foo function"""
print("a={}, b={}".format(a,b))

foo(1, 2, True, 7) # works, except if you use kind=Parameter.KEYWORD_ONLY above (py3 only)
foo(1, 2, new_arg1=True, new_arg2=7)
foo(a=3, b=4, new_arg1=False, new_arg2=42)
foo(new_arg2=-1,b=100,a='AAA')
foo(b=100,new_arg1=True,a='AAA')
foo.added_function()

help(foo)
它可以按您的预期工作:
new_arg1 True branch; new_arg2 is 7
a=1, b=2
new_arg1 True branch; new_arg2 is 7
a=1, b=2
new_arg1 False branch; new_arg2 is 42
a=3, b=4
new_arg1 False branch; new_arg2 is -1
a=AAA, b=100
new_arg1 True branch; new_arg2 is None
a=AAA, b=100
added_function
Help on function foo in module <...>:

foo(a, b, new_arg1=False, new_arg2=None)
This is my foo function
因此,您可以看到公开的签名符合预期,而您的用户看不到内部结构。请注意,您可以通过设置 kind=Parameter.KEYWORD_ONLY 将两个新参数设为“仅限关键字”。在新签名中,但您已经知道这在 python 2 中不起作用。
最后,您可能有兴趣使用 decopatch 使您的装饰器代码更具可读性和对无括号用法的健壮性。 .除其他外,它支持非常适合您的情况的“平面”样式,因为它删除了一层嵌套:
from decopatch import function_decorator, DECORATED

@function_decorator
def my_decorator(decorator_arg1=None, decorator_arg2=False, func=DECORATED):

# (1) capture the signature of the function to wrap ...
func_sig = signature(func)
# ...

# (2) create a wrapper with the new signature
@wraps(func, new_sig=new_sig)
def func_wrapper(*args, **kwds):
# Inside the wrapping function
...

# (3) add an attribute to the wrapper
def added_function():
# Do Something 2
print('added_function')

func_wrapper.added_function = added_function
return func_wrapper
(我也是这个的作者,创建它是因为我厌倦了嵌套和无括号处理)

关于python-2.7 - 如何将关键字参数添加到 Python 2.7 中的包装函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40980669/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com