This sounds a lot like this suggestion to add a nameof function/operator: https://mail.python.org/archives/list/python-ideas@python.org/thread/UUFFAI3FZMQRVPDCUPZEOAZCRNXKWFDE/#IHXME3F5XEQZAN6JSK2PMC4UOWV7AVSF
On Thu, Sep 17, 2020 at 10:37 PM Joseph Perez <jope...@hotmail.fr> wrote: > A lot of libraries use string for attribute names to do some "dynamic" > things. A typical example are SQLAlchemy [validators]( > https://docs.sqlalchemy.org/en/13/orm/mapped_attributes.html#simple-validators > ): > ```python > from sqlalchemy.orm import validates > > class EmailAddress(Base): > __tablename__ = 'address' > > id = Column(Integer, primary_key=True) > email = Column(String) > > @validates('email') # Here > def validate_email(self, key, address): > assert '@' in address > return address > > ``` > In this example of SQLAlchemy documentation, email validator use `"email"` > string in order to associate the validator to the `email` column. > > However this dynamic things don't play well with all static tools like > linters, but especially IDE (for usages finding, navigation, refactoring, > etc.), and of course type checkers. > > This issue could be solved with a "magic attribute" `__attrs__` (name can > be discussed), used the following way: > ```python > @dataclass > class Foo: > bar: int > > foo = Foo(0) > assert getattr(foo, Foo.__attrs__.bar) == 0 > assert getattr(foo, foo.__attrs__.bar) == 0 > ``` > To make it usable in class declaration, the `__attrs__` symbol should be > added to class declaration namespace: > ```python > class Foo: > bar: int > @validator(__attrs__.bar) > def validate(self): > ... > ``` > No check would be done by `__attrs__`, they are let to linters which would > integrate this language feature and check for the presence of the attribute > in the class/instance. > > And that becomes more interesting because type checkers could use this > feature to check dynamic attribute retrieving. > A special type `Attribute[Owner, T]` could be defined to be used by type > checkers such as `getattr` signature become: > ``` > # default parameter omitted for concision > def getattr(obj: Owner, attr: Attribute[Owner, T], /) -> T: > ... > ``` > (of course, `getattr` can still be used with strings, as the relation > between `Attribute` and `str` is explained later) > > It could allow to add typing to function like the following: > ```python > Key = TypeVar("Key", bound=Hashable) > def dict_by_attr(elts: Collection[T], key_attr: Attribute[T, Key]) -> > Mapping[Key, T]: > return {getattr(elt, key_attr): elt for elt in elts} > ``` > > Concerning the implementation of this feature would be very > straightforward, `__attrs__` being defined as a instance of a class: > ```python > class Attrs: > __slots__ = [] > def __getattribute__(self, name): > return name > ``` > Thus, `Foo.__attrs__.bar` would be simply equal to `"bar"`; `Attribute` > would be a special type, but backed by a `str`. hence there is no need to > modify `getattr` implementation or existing code using it. `Attribute` type > should then be a kind of `_SpecialForm`, compatible with string by the > "relation" `str` <=> `Attribute[Any, Any]` > The only modifications in the langage would be to add the `Attrs` class, > an `__attrs__` field to `type` and in class definition namespace when it is > evaluated. > The rest of the work (checking the attribute presence, type checking with > `Attribute[Owner, T]`) should be done by external tools (Pycharm, Mypy, > etc.) to handle the feature. > > To sum up, `__attrs__` would be a pseudo-static wrapper to attribute name > retrieving in order to benefit of static tools (refactoring, usages > finding, navigation, type checking), with a straightforward and backward > compatible implementation. > > And I don't see that as a "niche" feature, because a lot of libraries > could actually benefit from it (and SQLAlchemy, Pydantic, etc. are not a > small libraries). > > Joseph > _______________________________________________ > Python-ideas mailing list -- python-ideas@python.org > To unsubscribe send an email to python-ideas-le...@python.org > https://mail.python.org/mailman3/lists/python-ideas.python.org/ > Message archived at > https://mail.python.org/archives/list/python-ideas@python.org/message/UMPALRK3E2BL525V4C6KTTN5QV2NW3JY/ > Code of Conduct: http://python.org/psf/codeofconduct/ >
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/MKDUOTXKXAFR75QTWPVB6ZX53W6RQTGH/ Code of Conduct: http://python.org/psf/codeofconduct/