2 回答

TA貢獻1884條經驗 獲得超4個贊
有兩種方法可以實現此目的,具體取決于您的需要。他們最終都使用了 click?Context。
就我個人而言,我很喜歡選項 2,因為這樣我就不必修改函數簽名(而且我很少編寫多線程程序)。它聽起來也更像你正在尋找的東西。
選項 1:將上下文傳遞給函數
使用click.pass_context
裝飾器將單擊上下文傳遞給函數。
文件:
用法:https ://click.palletsprojects.com/en/7.x/commands/#nested-handling-and-contexts
API: https:?//click.palletsprojects.com/en/7.x/api/#click.pass_context
# test1.py
import click
@click.pass_context
def some_func(ctx, bar):
? ? foo = ctx.params["foo"]
? ? print(f"The value of foo is: {foo}")
@click.command()
@click.option("--foo")
@click.option("--bar")
def main(foo, bar):
? ? some_func(bar)
if __name__ == "__main__":
? ? main()
$ python test1.py --foo 1 --bar "bbb"
The value of foo is: 1
選項2:click.get_current_context()
通過 直接從當前線程中提取上下文click.get_current_context()
。從 Click 5.0 開始可用。
文件:
用法:https ://click.palletsprojects.com/en/7.x/advanced/#global-context-access
API:https ://click.palletsprojects.com/en/7.x/api/#click.get_current_context
注意:這僅在您位于當前線程(與最初用于設置單擊命令的線程相同的線程)中時才有效。
# test2.py
import click
def some_func(bar):
? ? c = click.get_current_context()
? ? foo = c.params["foo"]
? ? print(f"The value of foo is: {foo}")
@click.command()
@click.option("--foo")
@click.option("--bar")
def main(foo, bar):
? ? some_func(bar)
if __name__ == "__main__":
? ? main()
$ python test2.py --foo 1 --bar "bbb"
The value of foo is: 1

TA貢獻1786條經驗 獲得超11個贊
我想讓它更加無縫,所以我將它與修改函數的全局范圍的技巧結合起來,并提出了以下裝飾器:
def with_click_params(func):
? ? @functools.wraps(func)
? ? def wrapper(*args, **kwargs):
? ? ? ? g = func.__globals__
? ? ? ? sentinel = object()
? ? ? ? ctx = click.get_current_context()
? ? ? ? oldvalues = {}
? ? ? ? for param in ctx.params:
? ? ? ? ? ? oldvalues[param] = g.get(param, sentinel)
? ? ? ? ? ? g[param] = ctx.params[param]
? ? ? ? try:
? ? ? ? ? ? return func(*args, **kwargs)
? ? ? ? finally:
? ? ? ? ? ? for param in ctx.params:
? ? ? ? ? ? ? ? if oldvalues[param] is sentinel:
? ? ? ? ? ? ? ? ? ? del g[param]
? ? ? ? ? ? ? ? else:
? ? ? ? ? ? ? ? ? ? g[param] = oldvalues[param]
? ? return wrapper
你可以像這樣使用它(從@dthor的答案借用示例):
@with_click_params
def some_func():
? ? print(f"The value of foo is: {foo}")
? ? print(f"The value of bar is: {bar}")
@click.command()
@click.option("--foo")
@click.option("--bar")
def main(foo, bar):
? ? some_func()
if __name__ == "__main__":
? ? main()
這是它的實際效果:
$ python test2.py --foo 1 --bar "bbb"
The value of foo is: 1
The value of bar is: bbb
注意事項:
函數只能從
click
原始調用堆棧調用,但這是一個有意識的選擇(即,您將對變量注入做出假設)。點擊單元測試指南在這里應該很有用。該函數不再是線程安全的。
也可以明確要注入的參數名稱:
def with_click_params(*params):
? ? def wrapper(func):
? ? ? ? @functools.wraps(func)
? ? ? ? def inner_wrapper(*args, **kwargs):
? ? ? ? ? ? g = func.__globals__
? ? ? ? ? ? sentinel = object()
? ? ? ? ? ? ctx = click.get_current_context()
? ? ? ? ? ? oldvalues = {}
? ? ? ? ? ? for param in params:
? ? ? ? ? ? ? ? oldvalues[param] = g.get(param, sentinel)
? ? ? ? ? ? ? ? g[param] = ctx.params[param]
? ? ? ? ? ? try:
? ? ? ? ? ? ? ? return func(*args, **kwargs)
? ? ? ? ? ? finally:
? ? ? ? ? ? ? ? for param in params:
? ? ? ? ? ? ? ? ? ? if oldvalues[param] is sentinel:
? ? ? ? ? ? ? ? ? ? ? ? del g[param]
? ? ? ? ? ? ? ? ? ? else:
? ? ? ? ? ? ? ? ? ? ? ? g[param] = oldvalue
? ? ? ? return inner_wrapper
? ? return wrapper
@with_click_params("foo")
def some_func():
? ? print(f"The value of foo is: {foo}")
@click.command()
@click.option("--foo")
@click.option("--bar")
def main(foo, bar):
? ? some_func()
if __name__ == "__main__":
? ? main()
添加回答
舉報