Welcome, guest | Sign In | My Account | Store | Cart

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).

Python, 47 lines
 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.

Created by Nick Coghlan on Thu, 28 Jul 2011 (MIT)
Python recipes (4591)
Nick Coghlan's recipes (11)

Required Modules

  • (none specified)

Other Information and Tasks