Functions as Enum member values

Peter Otten __peter__ at web.de
Mon May 31 13:24:23 EDT 2021


On 31/05/2021 17:57, Colin McPhail via Python-list wrote:
> Hi,
> 
> According to the enum module's documentation an Enum-based enumeration's members can have values of any type:
> 
> 	"Member values can be anything: int, str, etc.."

You didn't read the fineprint ;)

"""
The rules for what is allowed are as follows: names that start and end 
with a single underscore are reserved by enum and cannot be used; all 
other attributes defined within an enumeration will become members of 
this enumeration, with the exception of special methods (__str__(), 
__add__(), etc.), descriptors (methods are also descriptors), and 
variable names listed in _ignore_
""""

Functions written in Python are descriptors and therefore cannot be 
used. Builtin functions aren't, leading to the following somewhat 
surprising difference:

 >>> def foo(self): print("foo")

 >>> class A(Enum):
	x = foo  # foo.__get__ exists -> foo is a descriptor
                  # the enum library assumes you are adding a
                  # method to your
                  # class, not an enumeration value.

	y = sum  # no sum.__get__ attribute -> function
                  # treated as an enumeration value.

 >>> list(A)
[<A.y: <built-in function sum>>]
 >>> A.x
<function foo at 0x012096A0>
 >>> A.y
<A.y: <built-in function sum>>
 >>> A.y.x()
foo

> I defined one with functions as member values. This seemed to work as long as the functions were defined ahead of the enumeration's definition. However I then noticed that my enumeration class was a bit weird: even although I could reference the enumeration's members individually by name I couldn't iterate through the members in the normal fashion - it seemed to have no members. Also, calling type() on a member gave the result <class 'function'> instead of the expected <enum 'enum name'>.
> 
> I am using Python 3.9.5 from python.org on macOS 11.4. Below is a small test script and its output. Are my expectations wrong or is there a problem with Enum?
> 
> Regards,
> Colin
> 
> -------------------------------
> from enum import Enum
> 
> def connect_impl():
>      print("message from connect_impl()")
> 
> def help_impl():
>      print("message from help_impl()")
> 
> class Command1(Enum):
>      CONNECT = 1
>      HELP = 2
> 
> class Command2(Enum):
>      CONNECT = connect_impl
>      HELP = help_impl
> 
> if __name__ == "__main__":
> 
>      def print_enum(cls, mbr):
>          print(f"{cls.__name__}\n  type(): {type(Command1)}")
>          print(f"  type of enum member: {type(mbr)}")
>          print(f"  number of members: {len(cls)}")
>          print("  enum members:")
>          if len(cls) > 0:
>              for c in cls:
>                  print(f"    {c}")
>          else:
>              print("    <none>")
>          print(f"  dir(): {dir(cls)}")
> 
>      member_1 = Command1.HELP
>      print_enum(Command1, member_1)
>      print()
> 
>      member_2 = Command2.HELP
>      print_enum(Command2, member_2)
>      print()
>      print("call Command2 member: ", end="")
>      member_2()
>      print()
> 
> -------------------------------
> (qt6) % python3 try_enum.py
> Command1
>    type(): <class 'enum.EnumMeta'>
>    type of enum member: <enum 'Command1'>
>    number of members: 2
>    enum members:
>      Command1.CONNECT
>      Command1.HELP
>    dir(): ['CONNECT', 'HELP', '__class__', '__doc__', '__members__', '__module__']
> 
> Command2
>    type(): <class 'enum.EnumMeta'>
>    type of enum member: <class 'function'>
>    number of members: 0
>    enum members:
>      <none>
>    dir(): ['__class__', '__doc__', '__members__', '__module__']
> 
> call Command2 member: message from help_impl()
> 
> (qt6) %
> -------------------------------
> 




More information about the Python-list mailing list