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?

200_success
146k22 gold badges190 silver badges478 bronze badges
asked Oct 6, 2017 at 13:32
\$\endgroup\$
1
  • \$\begingroup\$ What purpose does i serve? \$\endgroup\$ Commented Oct 7, 2017 at 1:28

3 Answers 3

14
\$\begingroup\$

The easiest solution would be to use the aenum 1 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.

answered Oct 6, 2017 at 15:17
\$\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\$ 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
answered Oct 6, 2017 at 14:28
\$\endgroup\$
1
  • \$\begingroup\$ thank you for your answer! very informative with perfect detail. i upvoted, but i accepted Ethan Furmans answer. \$\endgroup\$ 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)
answered May 7, 2021 at 6:51
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.