Search code examples
pythoninheritancesetattr

Inheritance without inheriting, is there create dinamically attributes that point to other class variables?




I'm struggling to solve with this problem.

I'd like to have the name variable to be like a pointer to the value of self.model.name. If the value of _class.model.name is changed the _class.name should change accordingly.

Can't find a way to basically map dynamically the Class attributes with any Model attributes without inheriting.

class Model(object):

    name = 'foo'
    parent = 'foo_p'

class Class(object):

    model_class = Model

    def __init__(self):

        self.model = self.model_class() 

        setattr(self, 'name', self.model.name)

_class = Class()
print _class.model.name # foo

_class.model.name = 'foo_1'        
print _class.name # this should be foo_1

Thanks!


Solution

  • Use a property to create a single dynamically computed attributes:

    class Class(object):
        _model_class = Model
    
        @property
        def name(self):
            return Class._model_class.name
    

    This causes all instances of Class to run the name method whenever the attribute name is looked up. This allows the value to be dynamically computed on each lookup.

    _class = Class()
    print(_class.name)  # 'foo'
    Model.name = 'bar'
    print(_class.name)  # 'bar'
    

    If you want to dynamically fetch many or all attributes from somewhere else, consider using __getattr__:

    class Class(object):
        _model_class = Model
    
        def __getattr__(self, name):
            # name is a *string* containing the name of the attribute to fetch
            return getattr(Class._model_class, name)
    

    The __getattr__ is only triggered for attributes that are not on the class/instance. This makes it rather straightforward to use with manually defined attributes. Note that you can use arbitrary code to restrict what is fetched - e.g. raise AttributeError if name is not in some whitelist.