gpt4 book ai didi

python - 装饰器如何在不更改其签名的情况下将变量传递给函数?

转载 作者:太空狗 更新时间:2023-10-29 21:52:41 25 4
gpt4 key购买 nike

首先让我承认,我想做的事情可能被认为是从愚蠢到邪恶的任何事情,但我想知道我是否可以用 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 个参数的函数,但显然这是行不通的。因此,您还必须向文档字符串添加一条消息,表明第一个参数不是接口(interface)的一部分,它只是一个实现细节,应该被忽略。不过,这有点糟糕。有没有什么办法可以做到这一点而不将这些变量卡在全局范围内的某些东西上?理想情况下,我希望它看起来像下面这样:

@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 的解决方案,我很满意。

最佳答案

你可以用一些技巧来做到这一点,将传递给装饰器的变量插入到函数的局部变量中:

import sys
from functools import wraps
from types import FunctionType


def is_python3():
return sys.version_info >= (3, 0)


def more_vars(**extras):
def wrapper(f):
@wraps(f)
def wrapped(*args, **kwargs):
fn_globals = {}
fn_globals.update(globals())
fn_globals.update(extras)
if is_python3():
func_code = '__code__'
else:
func_code = 'func_code'
call_fn = FunctionType(getattr(f, func_code), fn_globals)
return call_fn(*args, **kwargs)
return wrapped
return wrapper


@more_vars(a="hello", b="world")
def test(x, y):
print("locals: {}".format(locals()))
print("x: {}".format(x))
print("y: {}".format(y))
print("a: {}".format(a))
print("b: {}".format(b))


if __name__ == "__main__":
test(1, 2)

可以你这样做吗?当然! 应该你这样做吗?可能不是!

(可用代码 here .)

关于python - 装饰器如何在不更改其签名的情况下将变量传递给函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26746441/

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