Python结合了setattr和getattr

时间:2013-03-08 11:32:30

标签: python class getattr setattr

我想动态更新类的属性,但似乎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方法,但我想在可能的情况下压缩它。

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

感谢您的帮助

2 个答案:

答案 0 :(得分: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切换到values而不需要循环来创建len(values)的副本。

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

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

然后运行:

Container(attributes, values)

,无需在循环中调用setattr()

答案 1 :(得分: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实例。