1

我想动态更新一个类的属性,但似乎 setattr 和 getattr 的组合不起作用,因为我想使用它。

这是我的主要课程:

class Container(object):
    def __init__(self):
        pass
container = Container()
attributes = ['a', 'b', 'c', 'd']
values = [[1, 2, 3, 4, 5], [True, False], ['red', 'blue', 'green'], [0, 1, -1, -5, 99]]

请注意,出于该示例的目的,我明确构建了属性列表及其各自的值。但是,在这段代码的实际应用中,我事先并不知道任何事情。它们的编号、名称或值都不是。这需要动态地执行此操作。

这是其余的代码:

for key, value in zip(attributes, values):
    setattr(container, key, [])
    for val in value:
        setattr(container, key, getattr(container, key).append(val))

当我运行代码时,这部分不起作用。我可以将 getattr 部分保存在 tmp 变量中,然后在调用 setattr 之前调用列表的 append 方法,但如果可能的话,我想压缩它。

任何人都可以向我解释为什么这不起作用?我有什么选择?

谢谢你的帮助

4

2 回答 2

3

您正在就地附加到列表中。像所有就地突变函数一样,.append()返回None,所以你的最后一行:

setattr(container, key, getattr(container, key).append(val))

最终评估为:

setattr(container, key, None)

只需在类上设置列表的副本:

for key, value in zip(attributes, values):
    setattr(container, key, values[:])

其中,通过从 0 切片到简写符号来[:]创建副本,而无需循环。valueslen(values)

如果您要做的只是创建一个将键和值作为属性提供的对象(很像dict使用属性访问而不是项目访问的意愿),您还可以使用:

class Container(object):
    def __init__(self, names, values):
        self.__dict__.update(zip(names, values))

然后运行:

Container(attributes, values)

这消除了setattr()在循环中调用的需要。

于 2013-03-08T11:37:25.813 回答
1

如果您可以查看每个步骤的进度,它可能会帮助您了解发生了什么:

class Container(object):
    def __init__(self):
        pass
    def __str__(self):
        return '%s(%s)' % (self.__class__.__name__,
            ', '.join(['%s = %s' % (attr, getattr(self, attr))
                for attr in self.__dict__]))

现在你可以了print container。如果您在嵌套循环中执行此操作,您会看到在第一次尝试后setattr您已经破坏了存储在其中的原始列表container.a(如 Martijn 所述):

for key, value in zip(attributes, values):
    setattr(container, key, [])
    for val in value:
        print 'before:', container
        setattr(container, key, getattr(container, key).append(val))
        print 'after:', container

before: Container(a = [])
after: Container(a = None)
before: Container(a = None)
Traceback (most recent call last): ...

做到这一点的“最佳”方法显然取决于真正的问题——考虑到缩小问题 Martijn 的版本非常合适,但也许您必须在创建一些初始container实例之后的某个时间点附加一个项目或扩展多个项目。

于 2013-03-08T11:51:47.567 回答