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 <joperez@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-leave@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/