【问题标题】:Why using __dict__ in __setattr__ causing infinite loop in __getattr__为什么在 __setattr__ 中使用 __dict__ 会导致 __getattr__ 中的无限循环
【发布时间】:2019-01-09 03:40:03
【问题描述】:

我为这个指定的简化网格类编写了一个工作程序,但我无法使它适用于具有数十种方法/属性的真实类。 不能修改真实的Mesh类,也不能让Object类扩展Mesh。

这很好用:


    class Mesh:
        def __init__(self):
            self.hide_render = False


    class Object:
        def __init__(self, mesh_):
            self.mesh = mesh_

        def __getattr__(self, item):
            return self.mesh.__getattribute__(item) # infinite loop in this line

        def __setattr__(self, name, value):
            if name == 'hide_render': # line to replace----------
                self.mesh.__setattr__(name, value)
            else:
                super().__setattr__(name, value)

    ob = Object(Mesh())

    print(ob.hide_render)
    print(ob.mesh.hide_render)
    ob.mesh.hide_render = True
    print(ob.hide_render)
    print(ob.mesh.hide_render)
    ob.hide_render = False
    print(ob.hide_render)
    print(ob.mesh.hide_render)

输出:

    False
    False
    True
    True
    False
    False

但是当我想对真正的 Mesh 类做同样的事情时,通过将 setattr 方法中的第一行替换为: if name not in self.__dict__: 或者 if name in self.mesh.__dict__:

我在 getattr 方法中得到一个无限循环。 为什么?以及如何解决这个问题?

【问题讨论】:

  • 你认为设置self.mesh有什么作用?

标签: python getattr setattr


【解决方案1】:

self.mesh 不存在时,您的问题就会出现。如果您尝试将对 self.__dict__ 中尚不存在的对象的所有查找推迟到 self.mesh,则当您无法查找或分配给 self.mesh 本身时会遇到问题。

有几种方法可以解决这个问题。您可以使用来自__init__self.__dict__['mesh']super().__setattr__ 调用,而不是使用直接分配。或者您可以将名称 mesh 特殊化为 __setattr__

class Object:
    def __init__(self, mesh):
        self.mesh = mesh

    def __getattr__(self, name):
        return getattr(self.mesh, name)

    def __setattr__(self, name, value):
        if name in self.__dict__ or name == 'mesh':   # special case for 'mesh' here!
            super().__setattr__(name, value)
        else:
            setattr(self.mesh, name, value)

【讨论】:

  • 这毕竟不是我想要的。使用 dict 的意义在于对每个添加的属性进行多余的更正。我的意思是当我将 self.something = something 添加到 init 方法中时,我将不得不在 setattr 中添加一些特殊情况。如何避免这种情况?
  • 使用name in self.__dict__ 测试仅适用于实例字典中已经的属性。首先要将它们放入字典中,您需要做一些其他事情。如果没有更多信息,我无法详细说明我的答案,但您也许可以定义一个类级别列表或一组您要检查的名称。尝试使用name in self.list_of_names 代替name == "mesh"
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多