【问题标题】:setattr doesn't update the correct attribute of a class when using string使用字符串时 setattr 不会更新类的正确属性
【发布时间】:2018-02-06 10:01:53
【问题描述】:

我正在尝试使用setattr 和字符串更新类的属性。因此,例如使用以下代码:

class ClassA():
    def __init__(self):
        self.A = 0

class ClassB():
    def __init__(self):
        self.CA = ClassA()

CB = ClassB()
setattr(CB, "CA.A", 2)

print(CB.CA.A)

当我执行setattr(CB, "CA.A", 2) 时,它不会更新CBCA 类的属性A。相反,它会创建另一个属性,如图所示:

类中的 CB 名为 CA.A

然后当我打印 print(CB.CA.A) 时,我得到一个 0 值。 我不明白为什么会发生这种情况以及是否存在解决方案?

【问题讨论】:

    标签: python string setattr


    【解决方案1】:

    setattr() 采用文字属性名称。它不支持嵌套属性;名称中的. 只是名称中的一个点,而不是属性分隔符。

    换句话说,CB.CA.A = 2 中的.访问属性的语法,而不是属性名称的一部分。首先查找CB.CA,然后分配给结果中的A 属性。

    您需要在.上进行拆分,并使用单独的getattr()调用先获取父对象:

    setattr(getattr(CB, 'CA'), "A", 2)
    

    您可以将该逻辑包装到一个函数中:

    def setattr_nested(base, path, value):
        """Accept a dotted path to a nested attribute to set."""
        path, _, target = path.rpartition('.')
        for attrname in path.split('.'):
            base = getattr(base, attrname)
        setattr(base, target, value)
    

    【讨论】:

    • 嗬,我明白了。我喜欢 inception 函数:)
    • 但是,如果我尝试创建一个名称中带有点的变量,它会给我一个错误。那么为什么当我使用setattr 时它会创建一个名称中带有点的属性
    • @ymmx:通常,语法将您限制为有效的 Python 标识符(不能包含点)。那是因为点有特殊的含义。但setattr()getattr() 不限于这样的名字,你可以使用任何字符串。
    • 这与支持点的operator.attrgetter 有点不一致
    • @Mr_and_Mrs_D operator.attrgetter() 是这里的特例。
    猜你喜欢
    • 2019-02-04
    • 1970-01-01
    • 2013-06-17
    • 2017-09-27
    • 1970-01-01
    • 2012-10-13
    • 1970-01-01
    • 1970-01-01
    • 2018-04-03
    相关资源
    最近更新 更多