user278618
user278618

Reputation: 20222

Convert enum to int in python

I have an enum Nationality:

class Nationality:
        Poland='PL'
        Germany='DE'
        France='FR'

How can I convert this some enum to int in this or similar way:

position_of_enum = int(Nationality.Poland)  # here I want to get 0

I know that I can do it if I had code by:

counter=0
for member in dir(Nationality):
    if getattr(Nationality, member) == code:
        lookFor = member
        counter += 1
return counter

but I don't have, and this way looks too big for python. I'm sure that there is something much simpler .

Upvotes: 81

Views: 109076

Answers (12)

David Lotts
David Lotts

Reputation: 572

I would recommend using an enum. Instead of values of integers, use values of named-tuples with the integer as one of the tuple values. You can add any amount of data to your tuple. Add capital city, language, and population! The the enum and namedTuple work very well together:

from enum import Enum
from collections import namedtuple

Nat = namedtuple('Nat', ['id', 'abbr'])

class Nationality(Enum):
    Poland = Nat(0,'PL')
    Germany = Nat(1,'DE')
    France = Nat(2,'FR')

    def __int__(self):
        return self.value.id

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

The __int__ and __str__ are really optional, but allow you to use the int() and str() functions to access your id and abbr.

Look at all the functionality you get! The first one is what you wanted.

>>> position_of_enum = int(Nationality.Poland)  # here I want to get 0
>>> abbr_of_enum = str(Nationality.Poland)  #  "PL"
>>> print(position_of_enum,abbr_of_enum)
0 PL

>>> home=Nationality.France
>>> print(home)
FR

>>> print(int(home)) 
2

>>> print(home.name)
France

>>> print(home.value)
Nat(id=2, abbr='FR')

>>> print(home.value.id)
2

>>> print(home.value.abbr)
FR

Upvotes: 0

Thinkal VB
Thinkal VB

Reputation: 303

This method is something I am using

from enum import Enum
ClientType_DICT = {
    "1": 'webapp',
    "2": 'application',
    "3": 'embedded'
}
ClientType_ENUM: Enum = Enum('ClientType_ENUM', ClientType_DICT)
print(int(ClientType_ENUM('webapp').name))

@app.post("/example")
def login(device_type: ClientType_ENUM):
    deviceType = int(device_type.name) # print 1

Upvotes: 0

AboSari
AboSari

Reputation: 21

class Nationality(Enum):
    Poland = 'PL'
    Germany = 'DE'
    France = 'FR'

    @property
    def ordinal(self):
        return list(self.__class__).index(self)

    @classmethod
    def get(cls, index):
        return list(cls)[index]

and then:

>>> Nationality.Poland.ordinal
0

also

>>> Nationality.get(2)
Nationality.France

Upvotes: 2

andbmme
andbmme

Reputation: 91

One straightforward way to achieve this:

from enum import Enum

class Nationality(Enum):
    Poland= 1, 'PL'
    Germany= 2, 'DE'
    France= 3, 'FR'

    def __int__(self):
        return self.value[0]

    def __str__(self):
        return self.value[1]

# Example use
if __name__ == "__main__":
    print(int(Nationality.Poland))
    print(Nationality.Poland)
    print(int(Nationality.Poland) == 1)

Output:

>>> 1
>>> PL
>>> True

Explanation: You can create your enum with the desired numeration and string representation as you wish and you get the desired functionality by overwriting the respective __int__ and __str__ methods. To my knowledge, this does not break any contracts of enum and I prefer to keep functionality encapsulated in their respective classes.

Upvotes: 9

Morris
Morris

Reputation: 1126

from enum import Enum

class Phone(Enum):
    APPLE = 1 #do not write comma (,)
    ANDROID = 2

#as int:
Phone.APPLE.value

Need to access tuple by index if using commas:

class Phone(Enum):
    APPLE = 1, # note: there is comma (,)
    ANDROID = 2,

#as int:
Phone.APPLE.value[0]
   

Upvotes: 22

ban
ban

Reputation: 1679

Please use IntEnum

from enum import IntEnum

class loggertype(IntEnum):
    Info = 0
    Warning = 1
    Error = 2
    Fatal = 3

int(loggertype.Info)
0

Upvotes: 156

Andrzej Piasecki
Andrzej Piasecki

Reputation: 327

from enum import Enum

class Nationality(Enum):
    Poland = 'PL'
    Germany = 'DE'
    France = 'FR'

    @classmethod
    def get_index(cls, type):
        return list(cls).index(type)

and then:

Nationality.get_index(Nationality.Poland)
0

Upvotes: 3

Joe Kington
Joe Kington

Reputation: 284562

There are better (and more "Pythonic") ways of doing what you want.

Either use a tuple (or list if it needs to be modified), where the order will be preserved:

code_lookup = ('PL', 'DE', 'FR')
return code_lookup.index('PL') 

Or use a dictionary along the lines of:

code_lookup = {'PL':0, 'FR':2, 'DE':3}
return code_lookup['PL']  

The latter is preferable, in my opinion, as it's more readable and explicit.

A namedtuple might also be useful, in your specific case, though it's probably overkill:

import collections
Nationalities = collections.namedtuple('Nationalities', 
                                       ['Poland', 'France', 'Germany'])
nat = Nationalities('PL', 'FR', 'DE')
print nat.Poland
print nat.index(nat.Germany)

Upvotes: 14

Ethan Furman
Ethan Furman

Reputation: 69021

Using either the enum34 backport or aenum1 you can create a specialized Enum:

# using enum34
from enum import Enum

class Nationality(Enum):

    PL = 0, 'Poland'
    DE = 1, 'Germany'
    FR = 2, 'France'

    def __new__(cls, value, name):
        member = object.__new__(cls)
        member._value_ = value
        member.fullname = name
        return member

    def __int__(self):
        return self.value

and in use:

>>> print(Nationality.PL)
Nationality.PL
>>> print(int(Nationality.PL))
0
>>> print(Nationality.PL.fullname)
'Poland'

The above is more easily written using aenum1:

# using aenum
from aenum import Enum, MultiValue

class Nationality(Enum):
    _init_ = 'value fullname'
    _settings_ = MultiValue

    PL = 0, 'Poland'
    DE = 1, 'Germany'
    FR = 2, 'France'

    def __int__(self):
        return self.value

which has the added functionality of:

>>> Nationality('Poland')
<Nationality.PL: 0>

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

Upvotes: 44

janislaw
janislaw

Reputation: 300

I have seen something like:

PL, FR, DE = range(3)

Wrap it in a class and viola, you have a namespace for the enumeration.

Upvotes: 4

blubb
blubb

Reputation: 9890

You can't. Python does not store the order of class elements and dir() will return them in any order.

Seeing from your comment that you really do require a mapping from strings to integers, you should in fact do exactly that:

code_lookup = {
    'PL': ("Poland", 0), 
    'DE': ("Germany", 1), 
    'FR': ("France", 2), 
    ... 
}

Upvotes: 5

andrewdski
andrewdski

Reputation: 5505

Why don't you just define the values as numbers instead of strings:

class Nationality:
    POLAND = 0
    GERMANY = 1
    FRANCE = 2

If you need to access the two-letter names, you can simply provide a table that maps them. (Or a dictionary that maps the other way, etc.)

Upvotes: 7

Related Questions