> > Does the value stored in `a` know the name of that variable?
> Okay, I'm stumped - in what other language would it "know" (I assume this means automatically recording the string "a" as part of the object's state in some way)? Or is this just referring to debugging information added in some environments?
I'm partial to using descriptors to reference attribute names (as opposed to using arbitrary strings) so that refactoring tools recognize them. That looks roughly like:
_T_co = TypeVar("_T_co", covariant=True)
class Parameter(Generic[_T_co]):
"""
Here we push descriptors a bit further by using overloads to distinguish
type-level vs. instance-level references. Given:
```
class C:
param: Parameter[Param] = Param(...)
c = C(param=Param.VALUE)
```
`c.param` operates as attribute accesses normally do, invoking the
descriptor with `instance=c` and transparently returning `Param.VALUE`.
`C.param`, on the other hand, calls `__get__` with `instance=None`,
which is recognized by the overload as returning `Param` itself.
Thus `C.param.parameter_name` returns the string `param`, is typed
correctly, and if you need to find or update references to `param`
in the future, `setattr(c, C.param.parameter_name)` will be handled,
where `setattr(c, "param")` wouldn't have been.
"""
@overload
def __get__(self, instance: None, owner: type) -> Param: ...
@overload
def __get__(self, instance: Any, owner: type) -> _T_co: ...
def __get__(self, instance: object, owner: type) -> Param | _T_co: ...
def __set__(self, instance: object, value: Param | _T_co) -> None: ...
parameter_name: str
"""The parameter name this param has been assigned to."""
def __set_name__(self, _owner: type, parameter_name: str) -> None:
# Descriptor protocol to capture the field name as a string for reference
# later. This spares us having to write parameter names as strings, which
# is both error-prone and not future-proof.
# The type may be immutable, with dot assignment and normal setattr not
# available.
object.__setattr__(self, "parameter_name", parameter_name)
Neat. That actually was beyond what I'd committed to memory about the object/class model. But this only applies within a class body, which seems to be excluded in the article's example (since it isn't indented).
> Okay, I'm stumped - in what other language would it "know" (I assume this means automatically recording the string "a" as part of the object's state in some way)? Or is this just referring to debugging information added in some environments?
Python is (or can be) the anomaly here because of descriptors, specifically __set_name__: https://docs.python.org/3/reference/datamodel.html#object.__...
I'm partial to using descriptors to reference attribute names (as opposed to using arbitrary strings) so that refactoring tools recognize them. That looks roughly like: