0

I have complex python enum like the following:

from enum import Enum

class Properties:
    def __init__(self, name, v, k):
        self.name = name
        self.v = v
        self.k = k


class EnzymeNames(Enum):
    ENZYME_X = Properties("x", 0.2, 50)
    ENZYME_Y = Properties("y", 1.5, 100)

    @property
    def v(self):
        return self.value.v

    @property
    def k(self):
        return self.value.k

    def __str__(self):
        return self.value.name

Now currently, I have special function to get an enum by its name:

def get_enzyme(name) -> EnzymeNames:
    for e in EnzymeNames:
        if str(e) == name:
            return e

I was wondering is there any simple/pythonic way to access enum just by EnzymeNames('name') or similar?

Edit:

I think there is little confusion about what I am trying to achieve. I want to get EnzymeNames by property. For example, EnzymeNames('x') should give me EnzymeNames.ENZYME_X.

I have already tried following methods:

>>EnzymeNames('x')
ValueError: 'x' is not a valid EnzymeNames
>>EnzymeNames('ENZYME_X') 
ValueError: 'ENZYME_X' is not a valid EnzymeNames
>>EnzymeNames['ENZYME_X']
KeyError: 'ENZYME_X' 
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
Dexter
  • 1,421
  • 3
  • 22
  • 43

2 Answers2

1

Which enum are you using? Testing your code on Pythons 3.6, 3.5, 3.4, 3.3, and 2.7 (using the enum34 backport for 2.7 and 3.3) I get this:

>>> EnzymeNames['ENZYME_X']
x

In other words: using the built-in Enum or the enum34 backport your code works just fine.


A better way to write your enum is to integrate Properties into it:

from enum import Enum

class Properties:
    def __init__(self, v, k):
        self.v = v
        self.k = k


class EnzymeNames(Properties, Enum):

    X = 0.2, 50
    Y = 1.5, 100

    def __str__(self):
        return self.name

and in use:

>>> print(EnzymeNames.X)
X

>>> print(EnzymeNames.X.name)
X

>>> print(EnzymeNames.X.v)
0.2

>>> print(EnzymeNames.X.k)
50

>>> print(EnzymeNames['X'])
X

Some general tips for writing enums:

  • Keep the name singular; EnzymeName instead of EnzymeNames
  • Don't repeat the enum name in the enum member: X instead of ENZYME_X
  • If you're doing fancy stuff with Enum, consider using the Advanced Enum library (written by the same author as Enum and enum34)

Using aenum, your code might look like:

from aenum import Enum

class EnzymeName(Enum, init='v k'):

    X = 0.2, 50
    Y = 1.5, 100

    def __str__(self):
        return self.name
Ethan Furman
  • 63,992
  • 20
  • 159
  • 237
0

I suggest a slight reorganization of your code to use namedtuples. They are lightweight, easy to create objects that like enums, are immutable. See this post for a better explanation than I could put together on what they are.

Here is your code with two methods added to retrieve an instance via the Properties attribute values.

Code:

from enum import Enum
import collections
import math

Properties = collections.namedtuple('Properties', 'v k')

class EnzymeNames(Enum):
    x = Properties(0.2, 50)
    y = Properties(1.5, 100)

    @property
    def v(self):
        return self.value.v

    @property
    def k(self):
        return self.value.k

    @classmethod
    def from_v(cls, v):
        for en in cls:
            if math.isclose(en.v, v):
                return en

    @classmethod
    def from_k(cls, k):
        for en in cls:
            if math.isclose(en.k, k):
                return en

Test Code:

an_enzyme = EnzymeNames.from_k(100)
print(an_enzyme)
print('name:', an_enzyme.name)
print('k:', an_enzyme.k)
print('v:', an_enzyme.v)

Output:

EnzymeNames.y
name: y
k: 100
v: 1.5
Community
  • 1
  • 1
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135