我的目标是为多个对象属性设置可变类型(列表)的默认值。根据讨论here,我在None
的参数中将这些属性的默认值设置为__init__
,然后在[]
中为它们指定值__init__
如果他们采用了他们的默认值。以下是对此的表示:
class Wat(object):
def __init__(self, arg1=None, arg2=None, arg3=None):
for arg in arg1, arg2, arg3:
if arg == None:
arg = []
self.arg1 = arg1
self.arg2 = arg2
self.arg3 = arg3
def give(self, thing):
self.arg1.append(thing)
self.arg2.append(thing)
self.arg3.append(thing)
wat = Wat()
wat.give(5)
但是,这会引发以下异常:
AttributeError: 'NoneType' object has no attribute 'append'
。
我不知道wat.arg1
,wat.arg2
和wat.arg3
在调用None
时仍然可以有wat.give(5)
类型 - 他们应该已被重新分配到[]
中的__init__
。它必须与我对编码进行编码的方式有关,因为这有效:
class Wat(object):
def __init__(self, arg1=None, arg2=None, arg3=None):
if arg1 == None:
arg1 = []
if arg2 == None:
arg2 = []
if arg3 == None:
arg3 = []
self.arg1 = arg1
self.arg2 = arg2
self.arg3 = arg3
def give(self, thing):
self.arg1.append(thing)
self.arg2.append(thing)
self.arg3.append(thing)
wat = Wat()
wat.give(5)
在我看来,这两个语法在功能上是等价的,但你可以想象后一种语法如何变得非常繁琐和美学上令人不悦,因为以这种方式分配的参数数量会增加。
以前的语法有什么问题?我该如何解决?感谢。
编辑:你们当中有几个人已经发现了这个问题,但我仍然没有一个令人满意的解决方案。 @roippi提出了一种有效的方法,一次分配一个变量,但假设我有100个这些变量。如何在最少的代码行中完成此任务?这是循环的最初目的。谢谢大家。答案 0 :(得分:2)
for arg in arg1, arg2, arg3:
if arg == None:
arg = []
在此循环中,您将创建对arg1
,arg2
,arg3
指向的对象的新引用,并在检查它们对None
的值后指定这些对象变量(arg
)到新对象,因此旧对象仍然不变。所以,它大致相当于:
>>> lis = [1, 2, 3]
>>> x = lis[0] #now `x` points to lis[0]
>>> x = [] #now `x` points to a different object, this won't affect lis[0]
>>> lis
[1, 2, 3]
>>> x = lis[1]
>>> x = []
>>> lis
[1, 2, 3]
...
请注意,最好使用arg is None
而不是arg == None
。
答案 1 :(得分:1)
这是因为你将空列表分配给循环变量,循环变量在每次迭代时都会发生变化,即arg
与arg1
不是同一个变量,但它们在开始时共享相同的引用。迭代。
答案 2 :(得分:1)
如果所有变量都具有相同的行为,那么您可以使用setattr
在循环中设置属性,并使用locals()
来访问您的值。我使用inspect
获取所有变量名称,您可以对它们进行硬编码,或者进行评估,或者使用任何合理的方法:
import inspect
class Wat(object):
def __init__(self, arg1=None, arg2=None, arg3=None):
arg_spec, _v, _k, _d = inspect.getargspec(self.__init__)
for k in arg_spec[1:]:
value = locals()[k]
value = [] if value is None else value
setattr(self, k, value)
def give(self, thing):
self.arg1.append(thing)
self.arg2.append(thing)
self.arg3.append(thing)
>>> wat = Wat(arg2=[1,2])
>>> wat.give(5)
>>> wat2 = Wat()
>>> wat2.give(6)
>>> wat.__dict__
{'arg1': [5], 'arg2': [1, 2, 5], 'arg3': [5]}
>>> wat2.__dict__
{'arg1': [6], 'arg2': [6], 'arg3': [6]}
答案 3 :(得分:1)
编辑:你们中的一些人已经发现了这个问题,但我仍然没有 有一个令人满意的解决方案@roippi提出了一种有效的方法 一次分配一个变量,但假设我有100个变量 变量。如何在最少的代码行中完成此任务? 这是循环的最初目的。谢谢大家。
每当有人问这个问题时,他们就不可避免地使用了错误的数据结构。
例如,您可以使用**kwargs
方法捕获传递给Wat
对象的所有关键字参数。你可以从那里做你想做的事情,将kwargs
视为正常dict
。
class Wat(object):
def __init__(self, **kwargs):
self.arg1 = kwargs.get('arg1', [])
self.arg2 = kwargs.get('arg2', [])
self.arg3 = kwargs.get('arg3', [])
或
class Wat(object):
def __init__(self, **kwargs):
self.kwdict = kwargs
或者它们的某些组合:
class Wat(object):
def __init__(self, **kwargs):
self.kwdict = kwargs
self.kwdict['arg1'] = self.kwdict.get('arg1',[])
self.kwdict['arg2'] = self.kwdict.get('arg2',[])
self.kwdict['arg3'] = self.kwdict.get('arg3',[])
您甚至不关心参数名称,因此您可以使用*args
:
class Wat(object):
def __init__(self, *args):
self.args = list(args)
while len(self.args) < 3:
self.args.append([])
等
答案 4 :(得分:0)
怎么样
def default(x, fn):
return fn() if x is None else x
class Wat(object):
def __init__(self, arg1=None, arg2=None, arg3=None):
self.arg1 = default(arg1, list)
self.arg2 = default(arg2, list)
self.arg3 = default(arg3, list)