我不理解下面的例子,假设我有这些函数:

# python likes
def save(filename, data, **kwargs):
    fo = openX(filename, "w", **kwargs) # <- #1
    fo.write(data)
    fo.close()
# python doesnt like
def save2(filename, data, **kwargs):
    fo = openX(filename, "w", kwargs) # <- #2
    fo.write(data)
    fo.close()

def openX(filename, mode, **kwargs):
    #doing something fancy and returning a file object

为什么第一条是正确的,第二条是错误的?**kwargs基本上是一个字典,所以如果我想把参数传递给openX,我认为正确的方法是不使用**,只给出字典。但是Python显然不喜欢第二个,它告诉我我给了3个而不是2个参数。

这背后的原因是什么呢?


当前回答

扩展@gecco的回答,下面是一个例子,将向您展示两者的区别:

def foo(**kwargs):
    for entry in kwargs.items():
        print("Key: {}, value: {}".format(entry[0], entry[1]))

# call using normal keys:
foo(a=1, b=2, c=3)
# call using an unpacked dictionary:
foo(**{"a": 1, "b":2, "c":3})

# call using a dictionary fails because the function will think you are
# giving it a positional argument
foo({"a": 1, "b": 2, "c": 3})
# this yields the same error as any other positional argument
foo(3)
foo("string")

在这里,您可以看到解包字典是如何工作的,以及为什么发送实际的字典会失败

其他回答

下面的代码使用kwargs并将其转移到另一个函数:

def myprint( kwargs ):
    # default values
    a = kwargs.get('a', None)
    b = kwargs.get('b', None)

    # print both
    print('a={}, b={}'.format(a,b))

def mytest( **kwargs ):
    myprint( kwargs )

mytest()
mytest(b=2)

收益率:

a=None, b=None
a=None, b=2

因为字典是一个单独的值。如果希望将其作为一组关键字参数传递,则需要使用关键字展开。

对# 2 Args将只是一个带有dict值的形式形参,而不是关键字类型形参。

如果要将关键字类型参数传递给关键字参数 你需要在你的字典前指定**,这意味着**参数

有关使用**kw的更多详细信息,请查看此文件

http://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/

**语法告诉Python将关键字参数收集到字典中。save2将它作为一个非关键字参数(字典对象)传递下去。openX没有看到任何关键字参数,因此**args不会被使用。而是获得第三个非关键字参数(字典)。修改openX函数的定义。

def openX(filename, mode, kwargs):
    pass

扩展@gecco的回答,下面是一个例子,将向您展示两者的区别:

def foo(**kwargs):
    for entry in kwargs.items():
        print("Key: {}, value: {}".format(entry[0], entry[1]))

# call using normal keys:
foo(a=1, b=2, c=3)
# call using an unpacked dictionary:
foo(**{"a": 1, "b":2, "c":3})

# call using a dictionary fails because the function will think you are
# giving it a positional argument
foo({"a": 1, "b": 2, "c": 3})
# this yields the same error as any other positional argument
foo(3)
foo("string")

在这里,您可以看到解包字典是如何工作的,以及为什么发送实际的字典会失败