Почему использование __dict__ в __setattr__ вызывает бесконечный цикл в __getattr__

Я написал рабочую программу для этого указанного упрощенного класса Mesh, но я не могу заставить ее работать для реального класса с десятками методов / свойств. Я не могу изменить настоящий класс 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, имеет гораздо больше, чем атрибут hide _render, заменив первую строку в методе setattr на: if name not in self.__dict__:или же if name in self.mesh.__dict__:

Я получаю бесконечный цикл в методе getattr. Зачем? И как это решить?

1 ответ

Ваши проблемы возникают, когда self.mesh не существует Если вы пытаетесь отложить все поиски для объектов, которые еще не существуют в self.__dict__ в self.mesh, вы сталкиваетесь с проблемой, когда вы не можете искать или назначить self.mesh сам.

Есть несколько способов исправить это. Вы могли бы использовать self.__dict__['mesh'] или super().__setattr__ позвонить с __init__ вместо того, чтобы использовать прямое назначение. Или вы могли бы в особом случае имя 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)
Другие вопросы по тегам