[英]Passing kwargs through mutliple levels of functions, unpacking some of them but passing all of them
我在函數中有很多函數和很多變量,因為我正在制作模塊化 2D 繪圖。 為此,我希望能夠將 kwargs dict 向下傳遞到多層函數中。 舉個例子:
mydict = {'a':1,'b':2,'c':3}
def bar(b, c, **kwargs):
print("bar b=" + str(b))
print("bar c=" + str(c))
print("bar kwargs: ", kwargs)
def foo(a, b, **kwargs):
print("foo a=" + str(a))
print("foo b=" + str(b))
print("foo kwargs: ", kwargs)
bar(b, **kwargs)
foo(**mydict)
這將返回:
foo a=1
foo b=2
foo kwargs: {'c': 3}
bar b=2
bar c=3
bar kwargs: {}
這很好用,因為它捕獲了我不需要的所有 kwargs。 但是,我需要明確地將我在foo
中解壓縮的 kwargs 傳遞給bar
。 我想將整個mydict
傳遞到bar
中,就像我在foo
中所做的那樣,同時保持它的可讀性。
我現在能想到的唯一方法是通過mydict
兩次,我只解壓一次並在**_
中捕獲任何未使用的 kwarg,這看起來不太好。
mydict = {'a':1,'b':2,'c':3}
def bar(mydict, b, c, **_):
print("bar b=" + str(b))
print("bar c=" + str(c))
print("bar \'kwargs\': ", mydict)
def foo(mydict, a, b, **_):
print("foo a=" + str(a))
print("foo b=" + str(b))
print("foo \'kwargs\': ", mydict)
bar(mydict, **mydict)
foo(mydict, **mydict)
哪個返回
foo a=1
foo b=2
foo 'kwargs': {'a': 1, 'b': 2, 'c': 3}
bar b=2
bar c=3
bar 'kwargs': {'a': 1, 'b': 2, 'c': 3}
有沒有更好的方法來做到這一點?
讓函數只使用 **kwargs:
mydict = {'a':1,'b':2,'c':3}
def bar(**kwargs):
print("bar b=" + str(kwargs['b']))
print("bar c=" + str(kwargs['c']))
print("bar kwargs: ", kwargs)
def foo(**kwargs):
print("foo a=" + str(kwargs['a']))
print("foo b=" + str(kwargs['b']))
print("foo kwargs: ", kwargs)
bar(**kwargs)
foo(**mydict)
我認為您已經正確識別出代碼架構中的代碼異味。
dict 有內置方法
b = mydict.get("b") # or mydict['b']
或者可能具有更定制的功能
def get_b_c(b, c, **_):
return b, c
def bar(**kwargs):
b,c = get_b_c(**kwargs)
print("bar b=" + str(b))
print("bar c=" + str(c))
print("bar \'kwargs\': ", kwargs)
您發現的問題是需要重復傳遞相同的參數來對它們進行一些處理,這可以通過使用對象和一些附加方法來簡化。 參數在初始化時只解析一次。
class MyDrawing:
def __init__(self, **kwargs) -> None:
self.a = kwargs.get('a')
self.b = kwargs.get('b')
self.c = kwargs.get('c')
self.kwargs = kwargs # you probably don't need it, but here to match your example
def bar(self):
print("bar b=" + str(self.b))
print("bar c=" + str(self.c))
print("bar \'kwargs\': ", self.kwargs)
def foo(self):
print("foo a=" + str(self.a))
print("foo b=" + str(self.b))
print("foo \'kwargs\': ", self.kwargs)
self.bar()
drawing = MyDrawing(**mydict)
drawing.foo()
如果您不介意一些額外的垃圾傳遞,您可以在函數的開頭使用locals將您的參數收集到一個新的 dict 並使用 kwargs 更新它,然后將其傳遞給下一個函數
mydict = {'a':1,'b':2,'c':3}
def bar(b, c, **kwargs):
print("bar b=" + str(b))
print("bar c=" + str(c))
print("bar kwargs: ", kwargs)
def foo(a, b, **kwargs):
new_arg = locals()|kwargs
print("foo a=" + str(a))
print("foo b=" + str(b))
print("foo kwargs: ", kwargs)
bar(**new_arg)
foo(**mydict)
這導致
foo a=1
foo b=2
foo kwargs: {'c': 3}
bar b=2
bar c=3
bar kwargs: {'a': 1, 'kwargs': {'c': 3}}
對於舊版本的 python locals()|kwargs
相當於:
new_arg = {**locals(),**kwargs}`
或者
new_arg = dict(locals())
new_arg.update(kwargs)
@magic_copying_kwargs
def foo(a, b, /, **kwargs):
...
magic_copying_kwargs
裝飾器的定義如下:
import inspect
def magic_copying_kwargs(function):
parameters = inspect.signature(function).parameters
def _wrapper_function(**kwargs):
args = []
for name in parameters:
if name != 'kwargs':
try:
args.append(kwargs[name])
except KeyError:
raise TypeError(f'missing a required argument: {name!r}')
return function(*args, **kwargs)
return _wrapper_function
這假設 Python >=3.8,它具有僅位置參數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.