讓我先承認,我想要做的事情可能被認爲是愚蠢到邪惡,但我想知道我是否可以用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