3

I'm currently working with an enum of the following type:

class System(Enum):
  FIRST = 1
  SECOND = 2

Now I'd like to be able to do the following:

a = System.FIRST
url = a.getSystemURL()

where the url for the enumeration members FIRST and SECOND are different of course.

I could create a dictionary with the enumeration members as keys and the urls as values, but this won't assure that if I later add an enumeration member I'll remember to add corresponding the dictionary entry.

Is there a clean way to have an enumeration with multiple values for the enumeration members? And to name these different values?

Something like this:

class System(Enum):
  Values = (Value, url, something)
  FIRST = 1, 'https://www.example.com', 42
  SECOND = 2, 'https://www.test.com', 13

4 Answers 4

5

There is an example like this in the documentation. If the class defines an __init__ method, the enum values will be passed to it as arguments. This means you can define your enum like so:

class System(Enum):
    FIRST = 1, 'https://www.example.com', 42
    SECOND = 2, 'https://www.test.com', 13

    def __init__(self, value, url, something):
        self.value_ = value
        self.url = url
        self.something = something

(Note that value is a special attribute reserved by enums, so I named the attribute value_ to avoid a name clash.)

You can now access these attributes on each enum member:

>>> System.FIRST.url
'https://www.example.com'
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you. This is exactly what I was looking for! If I only use one property. Should I still add the ints to the definition? For the enum would you prefer just to put the url so enum_mem.value and enum_mem.url will give the same result?
@user9115052 I'd say it depends on your use case. Generally speaking, there's no need to have an integer associated with each enum value. But if you have a use for that integer in your program, go ahead and add it.
1

Both the stdlib Enum and aenum1 easily support your use case (although more work is required for the stdlib version).


stdlib enum 3.4+ (See the docs for __new__ and __init__ explanations.)

import enum
class System(enum.Enum):

    def __new__(cls, *args, **kwds):
        value = len(cls.__members__) + 1
        obj = object.__new__(cls)
        obj._value_ = value
        return obj

    def __init__(self, url, something):
        self.url = url
        self.something = something

    FIRST = 'https://www.example.com', 42
    SECOND = 'https://www.test.com', 13

aenum -- Usable for both Python 2 and 3 code. aenum also makes a few things easier -- the above code would be:

import aenum
class System(aenum.AutoNumberEnum):
    _init_ = 'url something'
    FIRST = 'https://www.example.com', 42
    SECOND = 'https://www.test.com', 13

And in use:

--> System.FIRST
<System.First: 1>

--> System.FIRST.url
'https://www.example.com'

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

Comments

0

Make the values a namedtuple.

from collections import namedtuple
from enum import Enum

Entry = namedtuple('Entry', ['value', 'url', 'something'])

class System(Enum):
  FIRST = Entry(1, 'https://www.example.com', 42)
  SECOND = Entry(2, 'https://www.test.com', 13)

print(System.FIRST.value.url)
# https://www.example.com

Comments

0

Have you tried the code you wrote? It already just works! Of course you don't really have multiple values, you have a single tuple value—but that isn't a problem:

>>> class System(Enum):
...     FIRST = 1, 'https://www.example.com', 42
...     SECOND = 2, 'https://www.test.com', 13
>>> _, url, _ = System.SECOND.value
>>> url
'https://www.example.com'
>>> a = System.FIRST
>>> url = a.value[1]
>>> url
'https://www.example.com'

There are things you can do to make this a little nicer, like using a namedtuple instead of a plain tuple so you can write a.value.url instead of a.value[1], but you've already written something that works.

Comments

Your Answer

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.