Почему использование __dict__ в __setattr__ вызывает бесконечный цикл в __getattr__ - PullRequest
0 голосов
/ 09 января 2019

Я написал рабочую программу для этого указанного упрощенного класса 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 Ответ

0 голосов
/ 09 января 2019

Ваши проблемы возникают, когда 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)
...