gpt4 book ai didi

Python 装饰器参数

转载 作者:行者123 更新时间:2023-12-01 02:05:22 24 4
gpt4 key购买 nike

我熟悉 python 装饰器,并且想知道一般情况。

假设我有一个生成人的函数:

def GeneratePerson(name, surname):
return {"name": name, "surname": surname}

现在,假设我想要一个装饰器来添加年龄:

def WithAge(fn):
def AddAge(*args):
person = fn(args[0], args[1])
person[age] = args[2]
return person
return AddAge

然后我会打电话

@AddAge
GeneratePerson("John", "Smith", 42)

但是,我发现这有点违反直觉。如果我查看“GeneratePerson”的签名,我会发现它只需要一个名字和一个姓氏参数。年龄(42)是装饰者要求的属性。我觉得语法(Java 风格)为:

@AddAge(42)
GeneratePerson("John", "Smith")

可能会更好。

我很感激我可以使用 kwargs 来解决这个问题,将堆栈调用为:

@WithAge
@AddGender
GeneratePerson(name="John", surname="Smith", age="42", gender="M")

但是有没有办法直接将参数传递给装饰器函数(例如:@Age(42),而不是必须通过装饰函数间接传递它?)

最佳答案

注意:装饰器是在定义时应用的,而不是在运行时应用的。这意味着你可以写的是:

@AddAge
def GeneratePerson(name, lastname):
...

这足以对您的最后一个问题回答“否”:不可能将参数传递给装饰器而不是装饰函数,除非您希望装饰函数的所有调用都相同。

但在 Python 3 中,可以向修饰函数添加参数:

def AddAge(param_name='age'):
# define the new parameter
param = inspect.Parameter(param_name,
inspect.Parameter.POSITIONAL_OR_KEYWORD)
def wrapper(f):
sig = inspect.signature(f)
params = list(sig.parameters.values())
params.append(param) # add the new parameter
sig2 = sig.replace(parameters = params) # to a new signature
def wrapped(*args, **kwargs):
bound = sig2.bind(*args, **kwargs) # process the parameters
args = bound.args # both positional
kwargs = bound.kwargs # and keywords
if param_name in kwargs: # extract the age
age = kwargs[param_name] # either keyword
del kwargs[param_name]
else:
args = list(args) # or positional
age = args.pop()
obj = f(*args, **kwargs) # call the original function
obj.age = age # add the attribute
return obj
wrapped.__signature__ = sig2 # attach the new signature
return wrapped
return wrapper

然后你就可以这样使用它

>>> f = AddAge()(GeneratePerson)
>>> p = f('John', 'Smith', 42)
>>> p.name
'John'
>>> p.lastname
'Smith'
>>> p.age
42

它甚至可以支持函数调用中的关键字:

>>> p = f('John', age=42, lastname="Smith")

将给出预期的结果。唯一的限制是原始函数不得有名为 age 的参数。如果有,您必须向装饰器传递一个不同的名称。

关于Python 装饰器参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49132405/

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