Reputation: 159
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?
Upvotes: 0
Views: 578
Reputation: 104822
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)
Upvotes: 2