class ComplexAttribute: """Base descriptor class for controlled access. It set value to modified inner name to avoid rewriting. """ _attr_template = "_attr#{}" inner_name: str outer_name: str def set_names(self, outer_name): self.inner_name = self._attr_template.format(outer_name) self.outer_name = outer_name def __get__(self, instance, owner): return self if instance is None else getattr(instance, self.inner_name) def __set__(self, instance, value): setattr(instance, self.inner_name, value) class ComplexEntityMeta(type): """Base metaclass for classes with complex attributes. Set inner and outer names for attributes announced with descriptors. """ def __init__(cls, name, bases, attr_dict): super().__init__(name, bases, attr_dict) for k, v in attr_dict.items(): if isinstance(v, ComplexAttribute): v.set_names(k) class ComplexEntity(metaclass=ComplexEntityMeta): """Base class for classes with complex attributes. Also present dict-like methods __contains__ and get. """ def __contains__(self, item): return self._get_key(item) in self.__dict__ def get(self, key, default=None): return self.__dict__.get(self._get_key(key), default) def _get_key(self, key): attr = self.__class__.__dict__.get(key) if isinstance(attr, ComplexAttribute): return attr.inner_name return key