Modifying __getattr__ to return a nested attribute instead of the named object I'm writing an application with two basic class types:

DocumentObject
Property (of document object).

Property instances are attributes of the DocumentObject class and The Property class has several simple attributes of its own (value, unit, etc.) and some methods.
In trying to make the scripting as user friendly as possible, I would like
objectName.propertyName
to return the value attribute of the Property instance, not the Property instance itself. Of course, it is possible to write objectName.propertyName.value but most of the time, the user will be interacting with the value, not the Property instance.
It seems it should be possible to implement this behaviour using modified __getattr__ and __setattr__ methods in DocumentObject like in the following example:
Input
class Property():
    def __init__(self, name, value, unit='mm'):
        self._name = name
        self.value = value
        self._unit = unit
        self._isVisible = True

    @property
    def name(self):
        return self._name

    @property
    def unit(self):
        return self._unit

    @property
    def isVisible(self):
        return self._isVisible

    @isVisible.setter
    def isVisible(self, value):
        self._isVisible = bool(value)


class DocumentObject():
    def __init__(self, properties):
        object.__setattr__(self, 'properties', dict())
        self.properties = properties
 
    def __getattr__(self, name):
        if &quot;properties&quot; in vars(self):
            if name in self.properties:
                return self.properties[name].value
            else: raise AttributeError
        else: raise AttributeError
 
    def __setattr__(self, key, value):
        if key in self.properties:
            self.properties[key].value = value
        else:
            object.__setattr__(self, key, value)
 

brick = DocumentObject({'length': Property('length',10), 'width': Property('width',5)})
print(brick.properties[&quot;length&quot;].name)
print(brick.length)

Output
length
10

Questions:

Is is good practice to do this?
Are there likely to be some negative consequences of this decision?
Is there a more elegant solution that I have missed?
Do not write trivial getters/setters; this is not Java/C++/etc. It's more Pythonic to simply have everything public under most circumstances. Private-ness is not enforced anyway and is more of a suggestion.
Consider using @dataclass
You can drop empty parens after your class definition
Under what circumstances would it be possible for properties to be missing from DocumentObject? I'm not sure why you check for this. Won't it always be in vars?
Use type hints.
Use snake_case, not camelCase for variables
Do not allow arbitrary __setattr__ on your DocumentObject other than to registered properties
Do not accept a dict with redundant keys; just accept an iterable of properties
IMO it's less surprising to have the document's actual properties dict override any request to a property named &quot;properties&quot; than the other way around

Suggested:
from dataclasses import dataclass
from typing import Dict, Iterable, Union


@dataclass
class Property:
    name: str
    value: float  # ?? or maybe Any
    unit: str = 'mm'
    is_visible: bool = True


PropDict = Dict[str, Property]


class DocumentObject:
    def __init__(self, properties: Iterable[Property]):
        self.properties: PropDict = {p.name: p for p in properties}
        self.__setattr__ = self._setattr

    def __getattr__(self, name: str) -&gt; Union[PropDict, float]:
        if name == 'properties':
            return self.properties
        return self.properties[name].value

    def _setattr(self, key: str, value: float):
        self.properties[key].value = value


brick = DocumentObject((
    Property('length', 10),
    Property('width', 5),
))
print(brick.properties['length'].name)
print(brick.length)
brick.width = 7
print(brick.width)