Python 对象属性的可变类型默认值的迭代赋值

Python 对象属性的可变类型默认值的迭代赋值,python,python-3.x,Python,Python 3.x,我的目标是为几个对象属性设置可变类型(列表)的默认值。根据讨论,我在\uuu init\uuu的参数中将这些属性的默认值设置为None,然后在\uu init\uu中为它们指定值[],如果它们采用默认值。这是一个代表: class Wat(object): def __init__(self, arg1=None, arg2=None, arg3=None): for arg in arg1, arg2, arg3: if arg == None:

我的目标是为几个对象属性设置可变类型(列表)的默认值。根据讨论,我在
\uuu init\uuu
的参数中将这些属性的默认值设置为
None
,然后在
\uu init\uu
中为它们指定值
[]
,如果它们采用默认值。这是一个代表:

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'对象没有属性“append”

我看不出
wat.arg1
wat.arg2
wat.arg3
在调用
wat.give(5)
时如何仍然具有类型
None
——它们应该被重新分配到
\uu init\uuuu
中的
[/code>。这一定与我对作业的编码方式有关,因为这是有效的:

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个变量。如何以最少的代码行完成此任务?这就是循环的最初目的。谢谢各位。

这是因为您将空列表分配给循环变量,循环变量在每次迭代时都会发生变化,即
arg
arg1
不是同一个变量,但它们在迭代开始时共享相同的引用。

这是因为您将空列表分配给循环变量,在每次迭代中发生变化的变量,即
arg
arg1
不是同一变量,但它们在迭代开始时共享相同的引用

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

在这个循环中,您正在创建对由
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

如何

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)
怎么样

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)

如果所有变量都具有相同的行为,则可以使用
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]}

如果所有变量都具有相同的行为,则可以使用
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]}
编辑:你们中的一些人已经发现了这个问题,但我仍然不知道 有一个令人满意的解决方案@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
        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([])
class Wat(对象):
定义初始化(self,*args):
self.args=列表(args)
而len(self.args)<3:
self.args.append([])
等等

编辑:你们中的一些人已经发现了这个问题,但我仍然不知道 有一个令人满意的解决方案@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
        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([])
class Wat(对象):
定义初始化(self,*args):
self.args=列表(args)
而len(self.args)<3:
self.args.append([])

等.

如果Ag1 ToRe[[]/COD>等,你可以只做<代码> Self.ARG1= ARG1等。跳过中间步骤。@ RoIPPI,考虑<代码>如果ALG1没有其他[]/Cord>,否则条件不相同。@ KROOLK如果你的类已经定义了多个伪值的行为,当然。否则,我认为这个区别是没有意义的。“RoPIPI,在另一种情况下,不会<代码> Self.Ag1= ARG1或[]/Cord>更简单吗?)你可以这么做