2 回答

TA貢獻(xiàn)1884條經(jīng)驗(yàn) 獲得超4個(gè)贊
有兩種方法可以實(shí)現(xiàn)此目的,具體取決于您的需要。他們最終都使用了 click?Context。
就我個(gè)人而言,我很喜歡選項(xiàng) 2,因?yàn)檫@樣我就不必修改函數(shù)簽名(而且我很少編寫多線程程序)。它聽起來也更像你正在尋找的東西。
選項(xiàng) 1:將上下文傳遞給函數(shù)
使用click.pass_context
裝飾器將單擊上下文傳遞給函數(shù)。
文件:
用法: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
選項(xiàng)2:click.get_current_context()
通過 直接從當(dāng)前線程中提取上下文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
注意:這僅在您位于當(dāng)前線程(與最初用于設(shè)置單擊命令的線程相同的線程)中時(shí)才有效。
# 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貢獻(xiàn)1786條經(jīng)驗(yàn) 獲得超11個(gè)贊
我想讓它更加無縫,所以我將它與修改函數(shù)的全局范圍的技巧結(jié)合起來,并提出了以下裝飾器:
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()
這是它的實(shí)際效果:
$ python test2.py --foo 1 --bar "bbb"
The value of foo is: 1
The value of bar is: bbb
注意事項(xiàng):
函數(shù)只能從
click
原始調(diào)用堆棧調(diào)用,但這是一個(gè)有意識(shí)的選擇(即,您將對(duì)變量注入做出假設(shè))。點(diǎn)擊單元測(cè)試指南在這里應(yīng)該很有用。該函數(shù)不再是線程安全的。
也可以明確要注入的參數(shù)名稱:
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()
添加回答
舉報(bào)