Using Enumerated Types in Python

栏目: IT技术 · 发布时间: 5年前

内容简介:By John Lekberg on June 06, 2020.This week's post is about using

Return to Blog

Using enumerated types in Python

By John Lekberg on June 06, 2020.

This week's post is about using enumerated types (enums) in Python. You will learn:

  • How to use enums to manage data that takes on a finite set of states.
  • How to impose a custom ordering on data.
  • How to represent a combination of states using Flag and IntFlag .

What are enums?

Enumerated types (enums) are sets of unique values. E.g. A tier list , with S-tier being the best, followed by A, B, C, D, and F:

import enum

Tier = enum.IntEnum("Tier", ["S", "A", "B", "C", "D", "F"])
list(Tier)
[<Tier.S: 1>, <Tier.A: 2>, <Tier.B: 3>, <Tier.C: 4>, <Tier.D: 5>,
 <Tier.F: 6>]
Tier.S < Tier.C
True
sorted([Tier.B, Tier.D, Tier.S, Tier.A, Tier.F, Tier.C])
[<Tier.S: 1>, <Tier.A: 2>, <Tier.B: 3>, <Tier.C: 4>, <Tier.D: 5>,
 <Tier.F: 6>]

In this case, using an IntEnum object is easier than using a string because the tiers compare correctly:

Tier.S < Tier.C
True
"S" < "C"
False
sorted([Tier.B, Tier.D, Tier.S, Tier.A, Tier.F, Tier.C])
[<Tier.S: 1>, <Tier.A: 2>, <Tier.B: 3>, <Tier.C: 4>, <Tier.D: 5>,
 <Tier.F: 6>]
sorted(["B", "D", "S", "A", "F", "C"])
['A', 'B', 'C', 'D', 'F', 'S']

And spelling mistakes are caught:

Tier.Z < Tier.Q
AttributeError: Z
"Z" < "Q"
False

Using an IntEnum object is easier than using an int because the IntEnum allows you to write mnemonics for the values:

Tier.S < Tier.C
True
1 < 4
True
sorted([Tier.B, Tier.D, Tier.S, Tier.A, Tier.F, Tier.C])
[<Tier.S: 1>, <Tier.A: 2>, <Tier.B: 3>, <Tier.C: 4>, <Tier.D: 5>,
 <Tier.F: 6>]
sorted([3, 5, 1, 2, 6, 4])
[1, 2, 3, 4, 5, 6]

When should I use enums?

I use enums when:

  • The data that I'm working with has a small number of states (e.g. "pass" or "fail").
  • The data has an ordering that doesn't work with strings (e.g. "S" before "A" in a tier list).
  • The data can be represented as a set of boolean flags (e.g. the flag register of a Zilog Z80 microprocessor ).

Here's code for each of these examples:

import random
import collections

Test = enum.Enum("Test", ["Pass", "Fail"])

row = lambda: [
    random.choice(list(Test)),
    random.choice(["Bobby", "Linda", "John"])
]
data = [ row() for _ in range(10) ]
data
[[<Test.Pass: 1>, 'John'],
 [<Test.Pass: 1>, 'Bobby'],
 [<Test.Fail: 2>, 'Linda'],
 [<Test.Fail: 2>, 'Bobby'],
 [<Test.Pass: 1>, 'Linda'],
 [<Test.Pass: 1>, 'Bobby'],
 [<Test.Pass: 1>, 'Linda'],
 [<Test.Pass: 1>, 'Bobby'],
 [<Test.Pass: 1>, 'Bobby'],
 [<Test.Pass: 1>, 'Bobby']]
[
    student
    for test, student in data
    if test == Test.Fail
]
['Linda', 'Bobby']
import random
import collections

Tier = enum.IntEnum("Tier", ["S", "A", "B", "C", "D", "F"])

data_tiers = random.choices(list(Tier), k=9)
data_names = ["Mario", "Link", "Samus", "Yoshi", "Kirby",
              "Fox", "Pikachu", "Ness", "Luigi"]
data = list(zip(data_tiers, data_names))
data
[(<Tier.B: 3>, 'Mario'),
 (<Tier.A: 2>, 'Link'),
 (<Tier.F: 6>, 'Samus'),
 (<Tier.B: 3>, 'Yoshi'),
 (<Tier.C: 4>, 'Kirby'),
 (<Tier.D: 5>, 'Fox'),
 (<Tier.A: 2>, 'Pikachu'),
 (<Tier.S: 1>, 'Ness'),
 (<Tier.A: 2>, 'Luigi')]
rankings = collections.defaultdict(set)

for tier, name in data:
    rankings[tier].add(name)

for tier in Tier:
    names = sorted(rankings[tier])
    print(f"{tier.name}-tier: {', '.join(names)}")
S-tier: Ness
A-tier: Link, Luigi, Pikachu
B-tier: Mario, Yoshi
C-tier: Kirby
D-tier: Fox
F-tier: Samus
import random

state = 0
for flag in Z80_Flag:
    # 50% chance that p is True.
    p = random.random() < 0.5
    if p:
        state |= flag

state
<Z80_Flag.Sign|Parity_Overflow|Subtract: 134>
for flag in Z80_Flag:
    if state & flag:
        status = "#"
    else:
        status = "."
    print(f"{flag.name:16} {status}")
Carry            .
Subtract         #
Parity_Overflow  #
Half_Carry       .
Zero             .
Sign             #

Python's support for enums

Python supports four different types of enums via the enum module:

Enum
IntEnum
IntFlag
Flag

What are the differences between these four?

Enum and Flag do not mix with integers. IntEnum and IntFlag do mix with integers.

import enum

Test = enum.Enum("Test", ["Pass", "Fail"])
IntTest = enum.IntEnum("IntTest", ["Pass", "Fail"])

Test.Pass + 0
TypeError: unsupported operand type(s) for +: 'Test' and 'int'
IntTest.Pass + 0
Z80 = enum.Flag("Z80", ["Carry", "Subtract", "Parity", "Zero"])
IntZ80 = enum.IntFlag("IntZ80", ["Carry", "Subtract", "Parity",
                                 "Zero"])

Z80.Carry | 2
TypeError: unsupported operand type(s) for |: 'Z80' and 'int'
IntZ80.Carry | 2
<IntZ80.Subtract|Carry: 3>

Enum and IntEnum represent states that can't be combined. Flag and IntFlag represent states that can be combined.

Test = enum.Enum("Test", ["Pass", "Fail"])
Z80 = enum.Flag("Z80", ["Carry", "Subtract", "Parity", "Zero"])

Test.Pass | Test.Fail
TypeError: unsupported operand type(s) for |: 'Test' and 'Test'
Z80.Carry | Z80.Zero
<Z80.Zero|Carry: 9>

In conclusion...

In this week's post you learned how to use enums to manage data that takes on a finite set of states. Enums allow you to impose a custom ordering on data and represent a combination of states using Flag and IntFlag .

My challenge to you:

Create an IntFlag that represents the input status of a standard NES controller .

If you enjoyed this week's post, share it with your friends and stay tuned for next week's post. See you then!


以上所述就是小编给大家介绍的《Using Enumerated Types in Python》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

白话大数据与机器学习

白话大数据与机器学习

高扬、卫峥、尹会生 / 机械工业出版社 / 2016-6 / 69

本书通俗易懂,有高中数学基础即可看懂,同时结合大量案例与漫画,将高度抽象的数学、算法与应用,与现实生活中的案例和事件一一做了关联,将源自生活的抽象还原出来,帮助读者理解后,又带领大家将这些抽象的规律与算法应用于实践,贴合读者需求。同时,本书不是割裂讲解大数据与机器学习的算法和应用,还讲解了其生态环境与关联内容,让读者更全面地知晓渊源与未来,是系统学习大数据与机器学习的不二之选: ·大数据产业......一起来看看 《白话大数据与机器学习》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具