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)