Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python函数;“记住”;前面的参数(**kwargs)_Python_Keyword Argument - Fatal编程技术网

Python函数;“记住”;前面的参数(**kwargs)

Python函数;“记住”;前面的参数(**kwargs),python,keyword-argument,Python,Keyword Argument,我有一些对象有一个属性字典,obj.attrs。为方便起见,这些对象的构造函数接受dict和/或**kwargs 看起来有点像这样: class Thing: def __init__(self, attrs={}, **kwargs): for arg in kwargs: attrs[arg] = kwargs[arg] self.attrs = attrs 这样Thing({'color':'red'})的作用与Thing(

我有一些对象有一个属性字典,
obj.attrs
。为方便起见,这些对象的构造函数接受dict和/或
**kwargs

看起来有点像这样:

class Thing:
    def __init__(self, attrs={}, **kwargs):
        for arg in kwargs:
            attrs[arg] = kwargs[arg]
        self.attrs = attrs
这样
Thing({'color':'red'})
的作用与
Thing(color='red')
相同

我的问题是,构造函数不知何故记住了传递给它的最后一个
attrs

例如:

>>> thing1 = Thing(color='red')
>>> thing2 = Thing()
>>> thing2.attrs
{'color': 'red'}
…但是
thing2.attrs
应该只是一个空的dict<代码>{}

这让我想知道使用
**kwargs
和类似
attrs={}
的参数是否都有问题

class Thing:
    def __init__(self, attrs = {}, **kwargs):
        self.attrs = {}
        # Don't write the loop yourself!
        self.attrs.update(attrs)
        self.attrs.update(kwargs)

有什么想法吗?

使用默认参数的问题是它们实际上只存在一个实例。当您在init方法定义中说
attrs={}
时,该默认{}实例是该方法每次调用的默认实例(它不会每次都生成一个新的默认空dict,它使用相同的dict)

问题是,如果只存在一个
attrs
,那么对于您所说的每一个实例
self.attrs=attrs
,每个实例的
self.attrs
成员变量都指向
attrs
的单个共享默认实例

另一个问题是,这不是完全多余吗?您可以使用
**kwargs
传入关键字/值参数或字典。如果您刚刚定义了这一点:

class Thing:
    def __init__(self, **kwargs):
        for arg in kwargs:
            self.attrs[arg] = kwargs[arg]
所有这些策略仍然有效:

thing1 = Thing(color='red')

thing2 = Thing(**{'color':'red'})

my_dict = {'color' : 'red'}
thing3 = Thing(**my_dict)
所以,如果你简单地用这种方式定义和使用事物,你将完全避免你的问题。

attrs
是字典的参考。创建新对象时,
self.attrs
指向该字典。当您从
kwargs
分配值时,该值将进入此词典

现在,当您创建第二个实例时,它是
self.attrs
也指向同一个字典。因此,它获取字典中的任何数据


有关这方面的详细讨论,请参见这里的stackoverflow。另请参见Python中的

您想将代码更改为:

class Thing:
    def __init__(self, attrs=None, **kwargs):
        attrs = {} if attrs is None else attrs
        for arg in kwargs:
            attrs[arg] = kwargs[arg]
        self.attrs = attrs
正如其他人指出的,默认参数的值在定义时计算一次,而不是每次调用函数时。通过使用可变容器,每个添加到容器中的内容都会被所有后续调用看到,因为每个调用都使用相同的容器作为默认值

可能您只使用attrs作为提供初始值的一种方式,而根本不打算共享dict。在这种情况下,请使用以下命令:

class Thing:
    def __init__(self, attrs=None, **kwargs):
        self.attrs = {}
        if attrs:
            self.attrs.update(attrs)
        for arg in kwargs:
            self.attrs[arg] = kwargs[arg]

更改签名以便每次都创建字典怎么样

class Thing:
    def __init__(self, attrs=None, **kwargs):
        self.attrs = attrs or {}
        self.attrs.update(kwargs)

仅仅为了它的价值-我们可以通过简单地不改变它来避免“
attrs
是一个共享可变对象”的问题。不要将
kwargs
转储到
attrs
中,而是将它们都转储到一个新的dict中。那么默认的参数对象将始终是
{}

class Thing:
    def __init__(self, attrs = {}, **kwargs):
        self.attrs = {}
        # Don't write the loop yourself!
        self.attrs.update(attrs)
        self.attrs.update(kwargs)

我之所以提到这一点,是因为每个人都争先恐后地描述“使用None作为默认参数并进行检查”这一习语,我个人认为这一习语相当刻薄。sgusc有一个正确的想法:考虑到Python的
**kwargs
:)的普遍魅力,整个努力都是无用的

与中的原理相同。所以我认为问题不是**kwargs,而是默认参数?正确。在使用默认参数时必须非常小心,因为当Python处理
def
语句时,默认参数的值会被创建一次,然后对同一默认值的引用会被反复使用。我认为另一个要点是,您想做的一切都可以用
kwargs
完成。您可能根本不需要
attrs
。因为它解释了问题并演示了解决方案而被接受。很高兴知道!真不敢相信我已经为Python编程3年了,却遇到了这个问题。真是令人伤心。现在我有一百个初始化例程要更改。。。谢谢你@blob8108:我对您真正想要做的事情有了另一个想法,并在上面对其进行了编辑。您可以说
attrs.update(kwargs)