NamedValue is a mixin class that modifies the signature of the class constructor to accept a name as the first positional argument and modifies repr() to display the name without affecting the result of str() (even for peer classes that rely on the str->repr fallback for their str implementation).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | class NamedValue:
# defining __slots__ in a mixin doesn't play nicely with builtin types
# so a low overhead approach would have to use collections.namedtuple
# style templated code generation
def __new__(cls, *args, **kwds):
name, *args = args
self = super().__new__(cls, *args, **kwds)
self._name = name
return self
def __init__(self, *args, **kwds):
name, *args = args
super().__init__(*args, **kwds)
@property
def __name__(self):
return self._name
def __repr__(self):
# repr() is updated to include the name and type info
return "{}({!r}, {})".format(type(self).__name__,
self.__name__,
super().__repr__())
def __str__(self):
# str() is unchanged, even if it relies on the repr() fallback
base = super()
base_str = base.__str__
if base_str.__objclass__ is object:
return base.__repr__()
return base_str()
# Example usage
>>> class NamedFloat(NamedValue, float):
... pass
...
>>> import math
>>> tau = NamedFloat('tau', 2*math.pi)
>>> tau
NamedFloat(tau, 6.283185307179586)
>>> print(tau)
6.283185307179586
>>> class NamedList(NamedValue, list):
... pass
...
>>> data = NamedList('data', [])
>>> data
NamedList('data', [])
>>> print(data)
[]
|
The concept of adding an enumeration class to the standard library came up on python-ideas (again). I don't like enumerations, as the grouping aspect seems largely redundant to me when we already have modules and classes to use as namespaces.
This recipe is a rough sketch of my counterproposal: a relatively simple way to name specific values such that their repr() includes the name, but their behaviour is otherwise unmodified.
(Note that an exec based solution, similar to that used for collections.namedtuple, could avoid the __dict__ overhead associated with the use of the mixin class in this recipe)
A factory function (with appropriate caching) could create appropriate subclasses implicitly based on the passed in values, simplifying creation to something like:
tau = namedvalue('tau', 2*math.pi) # No explicit NamedFloat class definition needed
The example uses 3.x style super() calls, but could be adapted for 2.x easily enough.