[Python-ideas] Add an attribute spec descriptor.
Eric Snow
ericsnowcurrently at gmail.com
Tue Jan 21 07:26:22 CET 2014
Here's something I've thought about off and on for a while.
Occasionally it would be useful to me to have a class attribute I can
use to represent an attribute that will exist on *instances* of the
class. Properties provide that to an extent, but they are data
descriptors which means they will not defer to like-named instance
attributes. However, a similar non-data descriptor would fit the
bill.
For the sake of clarity, here is a simple implementation that
demonstrates what I mean. I know it's asking a lot <wink>, but try to
focus on the idea rather than the code. I've posted a more complete
(and feature-rich) implementation online [1].
class Attr:
"""A non-data descriptor specifying an instance attribute."""
def __init__(self, name, doc=None):
self.__name__ = name
self.__doc__ = doc
def __get__(self, obj, cls):
if obj is None:
return self
else:
# The attribute wasn't found on the instance.
raise AttributeError(self.__name__)
def attribute(f=None):
"""A decorator that converts a function into an attribute spec."""
return Attr(f.__name__, f.__doc__)
def attrs(names):
"""A class decorator that adds the requested attribute specs."""
def decorator(cls):
for name in names:
attr = Attr(name)
setattr(cls, name, attr)
return cls
return decorator
Other features not shown here (see [1]):
* an optional "default" Attr value
* an optional "type" Attr (derived from f.__annotations__['return'])
* __qualname__
* auto-setting self.__name__ during the first Attr.__get__() call
* a nice repr
* Attr.from_func()
* proper ABC handling in attrs() (not an obvious implementation)
* optionally inheriting docstrings
Such a descriptor is particularly useful for at least 2 things:
1. indicating that an abstractproperty is "implemented" on *instances*
of a class
2. introspecting (on the class) all the attributes of instances of a class
Alternatives:
* "just use a property". As already noted, a property would work, but
is somewhat cumbersome in the case of writable attributes. A non-data
descriptor is a more natural fit in that case.
* for #1, "just use a normal class attribute". This would mostly
work. However, doing so effectively sets a default value, which you
may not want. Furthermore, it may not be clear to readers of the code
(or of help()) what the point of the class attr is.
Thoughts?
-eric
[1] https://bitbucket.org/ericsnowcurrently/odds_and_ends/src/default/attribute.py
[2] Where would Attr/attribute/attrs live in the stdlib? inspect? types?
More information about the Python-ideas
mailing list