让我先承认,我想要做的事情可能被认为是愚蠢到邪恶,但我想知道我是否可以用Python来做到这一点。装饰器如何将变量传递给函数而不更改其签名?
比方说,我有一个函数装饰器,它接受定义变量的关键字参数,并且我想在包装函数中访问这些变量。我可能会做这样的事情:
def more_vars(**extras):
def wrapper(f):
@wraps(f)
def wrapped(*args, **kwargs):
return f(extras, *args, **kwargs)
return wrapped
return wrapper
现在我可以这样做:
@more_vars(a='hello', b='world')
def test(deco_vars, x, y):
print(deco_vars['a'], deco_vars['b'])
print(x, y)
test(1, 2)
# Output:
# hello world
# 1 2
我不喜欢这个的事情是,当你使用这个装饰,你必须改变函数的调用签名,除了修饰装饰器外还增加额外的变量。另外,如果你看一下帮助功能,你看,你不希望在调用函数时使用一个额外的变量:
help(test)
# Output:
# Help on function test in module __main__:
#
# test(deco_vars, x, y)
这使它看起来像预期用户调用的函数有3个参数,但显然这是行不通的。所以你还必须向docstring添加一条消息,指出第一个参数不是接口的一部分,它只是一个实现细节,应该被忽略。虽然这很糟糕。有没有办法做到这一点,而不必将这些变量挂在全局范围内的某些东西上?理想情况下,我希望它看起来像下面这样:
@more_vars(a='hello', b='world')
def test(x, y):
print(a, b)
print(x, y)
test(1, 2)
# Output:
# hello world
# 1 2
help(test)
# Output:
# Help on function test in module __main__:
#
# test(x, y)
我满足于仅存在Python 3解决方案。
也许你应该描述你的需要更多。你只会得到一个装饰函数的机会,那么把'a ='hello''放在装饰器中有什么好处,而不是把它作为函数的第一行呢? – 2014-11-04 22:50:05
听起来好像你在问题已经被编译后如何在''test''中注入'extras',而不必以任何方式修改'test'的定义。如果是这样,我认为没有一些可怕的黑客攻击是不可能的。 – abarnert 2014-11-04 23:03:19
但使用[MacroPy](https://github.com/lihaoyi/macropy)宏而不是装饰器,我猜这会很容易...这是一个可以接受的答案吗? – abarnert 2014-11-04 23:03:51