0

I wrote a working program for this specified simplified Mesh class, but I can not make it work for real class with dozens of methods/properties. I can not modify real Mesh class, and I can not make Object class extended Mesh.

This works fine:


    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)

Output:

    False
    False
    True
    True
    False
    False

But when I want to do the same for real Mesh class with has much more than "hide _render" attribute by replacing the first line in setattr method with: if name not in self.__dict__: or if name in self.mesh.__dict__:

I get an infinite loop in a getattr method. Why? And how to solve this?

1 Answers1

2

Your problems occur when self.mesh doesn't exist. If you're trying to defer all lookups for objects that don't yet exist in self.__dict__ to self.mesh, you run into a problem when you can't lookup or assign to self.mesh itself.

There are a few ways you could fix that. You could use self.__dict__['mesh'] or a super().__setattr__ call from __init__ rather than using a direct assignment. Or you could special case the name mesh in __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)
Blckknght
  • 100,903
  • 11
  • 120
  • 169
  • That is not what I was looking for after all. Sens of using __dict__ was to make redundant corrections on every added property unnecessary. I mean when I will add self.something = something into init method, I will have to add something as another special case in setattr. How to avoid this? – Piotr Kowalczyk Jan 19 '19 at 21:52
  • Using the `name in self.__dict__` test only works for attributes that are *already* in the instance dictionary. To get them into the dictionary in the first place, you need to do something else. Without more information, I can't really elaborate on my answer, but you could perhaps define a class level list or set of names that you'd check. Try something like `name in self.list_of_names` in place of `name == "mesh"`. – Blckknght Jan 25 '19 at 20:19