14
\$\begingroup\$

In Python >= 3.6 there is an enum.auto() function.

The auto() function can be used like this:

import enum
from enum import auto

class Fruits(enum.Enum):
  APPLE = auto()
  ORANGE = auto()
  BANANA = auto()

I want to use it, but i cannot be sure if i am on Python >= 3.6 so I implemented it like this:

import enum

try:
  from enum import auto
except ImportError: 
  __my_enum_auto_id = 0
  def auto() -> int:
    global __my_enum_auto_id
    i = __my_enum_auto_id
    __my_enum_auto_id += 1
    return i

class Fruits(enum.Enum):
  APPLE = auto()
  ORANGE = auto()
  BANANA = auto()

It works afaik, but it seems ugly to me. Any suggestions on how to improove it/make it better? or is it ok?

Is there some side effect I may have overlooked?

\$\endgroup\$
1
  • \$\begingroup\$ What purpose does i serve? \$\endgroup\$
    – chepner
    Commented Oct 7, 2017 at 1:28

3 Answers 3

14
\$\begingroup\$

The easiest solution would be to use the aenum1 library, which is drop-in compatible with the stdlib and also has some advanced features not found in the stdlib. It also works in Python versions 2.7 and 3.3+.


1 Disclosure: I am the author of the Python stdlib Enum, the enum34 backport, and the Advanced Enumeration (aenum) library.

\$\endgroup\$
1
  • \$\begingroup\$ thank you very much! i didnt knew about aenum. and thank you for your effort in general on the stdlib and so on; you do a great work! \$\endgroup\$
    – linluk
    Commented Oct 7, 2017 at 10:25
11
\$\begingroup\$

Honestly, you won't be able to get anything as good as the built-in code for auto. This is as they've added a clause to _EnumDict.__setitem__ to handle the class.

Since we can't make it so that the values from auto don't start at one for each enum. Such as the following being equivalent:

class A(Enum):
    A = auto()
    B = auto()

class B(Enum):
    A = auto()
class A(Enum):
    A = 1
    B = 2

class B(Enum):
    A = 1

And so the simplest would be to stick with your code, and have the following be equal. (As you done)

class A(Enum):
    A = auto()
    B = auto()

class B(Enum):
    A = auto()
class A(Enum):
    A = 1
    B = 2

class B(Enum):
    A = 3

And so IMO your code is good. The only thing I'd change is make your code not pollute the global namespace with __my_enum_auto_id. And indent with four spaces. This is as easy as using a closure.

def auto_builder():
    number = 0
    def auto():
        nonlocal number
        number += 1
        return number
    return auto

try:
    from enum import auto
except ImportError: 
    auto = auto_builder()
del auto_builder
\$\endgroup\$
1
  • \$\begingroup\$ thank you for your answer! very informative with perfect detail. i upvoted, but i accepted Ethan Furmans answer. \$\endgroup\$
    – linluk
    Commented Oct 7, 2017 at 10:27
2
\$\begingroup\$

My only suggestion would be to user itertools.count() instead of implementing your own counter. Something like:

from itertools import count

_global_counter = count()

def auto():
    return next(_global_counter)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.