Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can named arguments be used with Python enums?

Tags:

Example:

class Planet(Enum):      MERCURY = (mass: 3.303e+23, radius: 2.4397e6)      def __init__(self, mass, radius):         self.mass = mass       # in kilograms         self.radius = radius   # in meters 

Ref: https://docs.python.org/3/library/enum.html#planet

Why do I want to do this? If there are a few primitive types (int, bool) in the constructor list, it would be nice to used named arguments.

like image 983
kevinarpe Avatar asked Nov 01 '14 18:11

kevinarpe


People also ask

Can Python enums have methods?

Customize Python enum classes Python enumerations are classes. It means that you can add methods to them, or implement the dunder methods to customize their behaviors.

Can enums have the same value Python?

By definition, the enumeration member values are unique. However, you can create different member names with the same values.

How does enum work in Python?

Enum is a class in python for creating enumerations, which are a set of symbolic names (members) bound to unique, constant values. The members of an enumeration can be compared by these symbolic anmes, and the enumeration itself can be iterated over.

Should enums be capitalized Python?

By convention, enumeration names begin with an uppercase letter and are singular. The enum module is used for creating enumerations in Python.


2 Answers

While you can't use named arguments the way you describe with enums, you can get a similar effect with a namedtuple mixin:

from collections import namedtuple from enum import Enum  Body = namedtuple("Body", ["mass", "radius"])  class Planet(Body, Enum):      MERCURY = Body(mass=3.303e+23, radius=2.4397e6)     VENUS   = Body(mass=4.869e+24, radius=6.0518e6)     EARTH   = Body(mass=5.976e+24, radius=3.3972e6)     # ... etc. 

... which to my mind is cleaner, since you don't have to write an __init__ method.

Example use:

>>> Planet.MERCURY <Planet.MERCURY: Body(mass=3.303e+23, radius=2439700.0)> >>> Planet.EARTH.mass 5.976e+24 >>> Planet.VENUS.radius 6051800.0 

Note that, as per the docs, "mix-in types must appear before Enum itself in the sequence of bases".

like image 194
Zero Piraeus Avatar answered Oct 05 '22 13:10

Zero Piraeus


The accepted answer by @zero-piraeus can be slightly extended to allow default arguments as well. This is very handy when you have a large enum with most entries having the same value for an element.

class Body(namedtuple('Body', "mass radius moons")):     def __new__(cls, mass, radius, moons=0):         return super().__new__(cls, mass, radius, moons)     def __getnewargs__(self):         return (self.mass, self.radius, self.moons)  class Planet(Body, Enum):      MERCURY = Body(mass=3.303e+23, radius=2.4397e6)     VENUS   = Body(mass=4.869e+24, radius=6.0518e6)     EARTH   = Body(5.976e+24, 3.3972e6, moons=1) 

Beware pickling will not work without the __getnewargs__.

class Foo:     def __init__(self):         self.planet = Planet.EARTH  # pickle error in deepcopy  from copy import deepcopy  f1 = Foo() f2 = deepcopy(f1)  # pickle error here 
like image 24
shao.lo Avatar answered Oct 05 '22 13:10

shao.lo