簡體   English   中英

通過多級函數傳遞 kwargs,解包其中一些但傳遞所有函數

[英]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)

我認為您已經正確識別出代碼架構中的代碼異味。

(不推薦)從 kwargs 中提取變量的函數

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM