23

Python 3.4 has a new enum module and Enum data type. If you are unable to switch to 3.4 yet, Enum has been backported.

Since Enum members support docstrings, as pretty much all python objects do, I would like to set them. Is there an easy way to do that?

Ethan Furman
  • 57,917
  • 18
  • 142
  • 218

2 Answers2

10

Yes there is, and it's my favorite recipe so far. As a bonus, one does not have to specify the integer value either. Here's an example:

class AddressSegment(AutoEnum):
    misc = "not currently tracked"
    ordinal = "N S E W NE NW SE SW"
    secondary = "apt bldg floor etc"
    street = "st ave blvd etc"

You might ask why I don't just have "N S E W NE NW SE SW" be the value of ordinal? Because when I get its repr seeing <AddressSegment.ordinal: 'N S E W NE NW SE SW'> gets a bit clunky, but having that information readily available in the docstring is a good compromise.

Here's the recipe for the Enum:

class AutoEnum(enum.Enum):
    """
    Automatically numbers enum members starting from 1.

    Includes support for a custom docstring per member.
    """
    #
    def __new__(cls, *args):
        """Ignores arguments (will be handled in __init__."""
        value = len(cls) + 1
        obj = object.__new__(cls)
        obj._value_ = value
        return obj
    #
    def __init__(self, *args):
        """Can handle 0 or 1 argument; more requires a custom __init__.

        0  = auto-number w/o docstring
        1  = auto-number w/ docstring
        2+ = needs custom __init__

        """
        if len(args) == 1 and isinstance(args[0], (str, unicode)):
            self.__doc__ = args[0]
        elif args:
            raise TypeError('%s not dealt with -- need custom __init__' % (args,))

And in use:

>>> list(AddressSegment)
[<AddressSegment.ordinal: 1>, <AddressSegment.secondary: 2>, <AddressSegment.misc: 3>, <AddressSegment.street: 4>]

>>> AddressSegment.secondary
<AddressSegment.secondary: 2>

>>> AddressSegment.secondary.__doc__
'apt bldg floor etc'

The reason I handle the arguments in __init__ instead of in __new__ is to make subclassing AutoEnum easier should I want to extend it further.

Ethan Furman
  • 57,917
  • 18
  • 142
  • 218
  • Sorry, I don't understand what constitutes the docstring here. Are you defining four enums named "misc", "ordinal", "secondary", and "street"? – Noumenon Nov 19 '19 at 04:18
  • @Noumenon: Yes, four members are being created, and the docstring for each is the text that follows. The value of the four members is `1`, `2`, `3`, and `4`, respectively. – Ethan Furman Dec 22 '21 at 19:12
-4

Functions and classes have docstrings, but most objects don't and do not even need them at all. There is no native docstring syntax for instance attributes, as they can be described exhaustively in the classes' docstring, which is also what I recommend you to do. Instances of classes normally also don't have their own docstrings, and enum members are nothing more than that.

Sure enough you could add a docstring to almost anything. Actually you can, indeed, add anything to almost anything, as this is the way python was designed. But it is neither useful nor clean, and even what @Ethan Furman posted seems like way to much overhead just for adding a docstring to a static property.

Long story short, even though you might not like it at first: Just don't do it and go with your enum's docstring. It is more than enough to explain the meaning of its members.

Ethan Furman
  • 57,917
  • 18
  • 142
  • 218
Bachsau
  • 1,090
  • 11
  • 22
  • 1
    Though I agree they are not *needed* docstrings serve an important purpose. Some enums may require a more detailed descriptions, thus why this question exists. Overall this answer shows a complete lack of understanding of the purpose of documenting code. – Error - Syntactical Remorse Dec 17 '19 at 14:14
  • @Error-SyntacticalRemorse Of course I understand the purpose of documenting code. However I would expect that documentation at a common place, which for class attributes is the classes docstring. Enums are classes defining a set of possible values. The right place to describe its purpose together with the meaning of any possible value is the docstring of the enum. Wanting to build a hack to allow something unexpected and completely uncommon shows a complete lack of understanding of the purpose of standards and clean code. ;) – Bachsau Dec 17 '19 at 14:33
  • It should be both (in the case of enums). The class should be documented but there are times where documenting the attributes is extremely useful as well. Take for example http response codes. They could be stored as enums but it would be useful to comment what the code means beyond the simple enum name. Same goes for things such as regex expressions which can also be stored as enums. – Error - Syntactical Remorse Dec 17 '19 at 17:00