Рубрики
Без рубрики

Почему вам нужны enums и как их использовать в Python

Узнайте, как Enum может помочь вам моделировать несколько концепций реального мира. Теги с Python.

Допустим, у вас есть объект пользователя с двумя атрибутами: Имя и тип .

Тип пользователя может быть Админ С Модератор и Клиент Отказ

Как бы вы смоделировали это?

Используя кортеж

Один из способов – использовать кортеж для проведения значений типа:

from dataclasses import dataclass

USER_TYPES = (
    "Customer",
    "Moderator",
    "Admin",
)

@dataclass
class User:
    name: str
    type: str

Давайте попробуем и посмотрим, может ли кортеж сделать работу:

# Admin
user_a = User("Christian", USER_TYPES[2])

# Customer
user_b = User("Daniel", USER_TYPES[0])

user_a.type == user_b.type
# False

# Ideally it should be USER_TYPES 😞
type(user_a.type)
# 

# Ideally this should be False 😞
user_a.type == "Admin"
# True

len(USER_TYPES)
# 3

[user_type for user_type in USER_TYPES]
# ['Customer', 'Moderator', 'Admin']

if user_b.type:
    print("User is valid")
else:
    print("Not a valid user")
# User is valid

Это хорошая первая попытка, но есть несколько предостережений, которые я хочу обратиться:

  • Тип (user_a.type) это ул И не User_types.
  • user_a.type это Истинный
  • Кто помнит, что User_types [2] является?

Адресация последней точки легко, но первые два хитрыми: Мне нужно отдельную USERTYPE Из его бетонного представления (в этом случае строка) Отказ

Используя константы

Другой подход к рассмотрению – это назначить числовые значения для Константы 1 :

from dataclasses import dataclass

CUSTOMER, MODERATOR, ADMIN = range(0,3)

@dataclass
class User:
    name: str
    type: int
user_a = User("Christian", ADMIN)
user_b = User("Daniel", CUSTOMER)

user_a.type == user_b.type
# False

type(user_1.type)
# 

user_a.type == "admin"
# False

# Ideally this should be False 😞
user_b.type == 0
# True

if user_b.type == CUSTOMER:
    print("User type: CUSTOMER")
# User type: CUSTOMER

# `user_b.type` should evaluate to True 😞
if user_b.type:
    print("User is valid")
else:
    print("Not a valid user")
# Not a valid user

Использование Константы Действительно улучшает читаемость: Теперь я могу использовать Клиент , Модератор и Админ Отказ

Но у него также есть некоторые (новые) недостатки:

  • user_b.type и Клиент являются 0 , Так что это оценивается до фальсификатор
  • Тип (user_a.type) это int И не Usertype.
  • user_b.type правда
  • len (user_types) Ушел, у меня нет способа ссылаться на коллекцию типов пользователя

Используя класс

Используя Класс USERTYPE может быть способ унифицировать мои первые две попытки.

from dataclasses import dataclass

class UserType:
    CUSTOMER = 0
    MODERATOR = 1
    ADMIN = 2

@dataclass
class User:
    name: str
    # NOTE: type is not UserType 😞
    type: int

Давайте посмотрим, как USERTYPE ведет себя:

user_a = User(name="Christian", type=UserType.ADMIN)
user_b = User(name="Daniel", type=UserType.CUSTOMER)

user_a.type == user_b.type
# False

type(user_a.type)
# 

user_a.type == "ADMIN"
# False

user_b.type == 0
# True

len(UserType)
# Traceback (most recent call last):
#   File "", line 1, in 
# TypeError: object of type 'type' has no len()

if user_b.type:
    print("User is valid")
else:
    print("Not a valid user")
# Not a valid user 😞

[user_type for user_type in UserType]
# Traceback (most recent call last):
#   File "", line 1, in 
# TypeError: 'type' object is not iterable

Я сгруппировал ценности вместе, под USERTYPE И это определенно более читаемо, чем раньше.

Но есть еще несколько недостатков, похожих на кортеж выполнение:

  • Базовый тип бетона для каждого значения – int. Итак, вы можете сравнить USERTYPE. Клиент другому INTS.
  • USERTYPE. Клиент является фальсию, потому что его значение – 0.
  • Классы мультиплины, и тот факт, что я могу изменить класс во время выполнения не то, что я хочу

Имея класс, который инкапсулирует концепцию типа/категорию, полезно, но простой класс оставляет нас на полпути.

Мне нужен (новый) тип, который поддерживает перечисление, то, что я могу рассчитывать, идеально неизменно.

И мне нужен (новый) тип, где базовое представление как-то абстрагировано, например:

type(UserType.ADMIN) is str
# False

type(UserType.ADMIN) is int
# False

Тип, который мне нужен, называется Enum и Python поддерживает Enum они были введены с PEP 435 И они являются частью стандартной библиотеки.

От PEP 435: перечисление – это набор символических имен, связанных с уникальными, постоянными значениями. В пределах перечисления значения могут сравниться с идентичностью, а сама перечисление может быть передано.

Используя enums.

Типы Enum – это типы данных, которые содержат статический, заказанный набор значений Отказ

Пример типа Enum может быть дни недели или набор значений состояния для части данных (например, тип моего пользователя).

from dataclasses import dataclass
from enum import Enum

class UserType(Enum):
    CUSTOMER = 0
    MODERATOR = 1
    ADMIN = 2

@dataclass
class User:
    name: str
    type: UserType
# exactly like with the class example
user_a = User(name="Christian", type=UserType.ADMIN)
user_b = User(name="Daniel", type=UserType.CUSTOMER)

user_a.type == user_b.type
# False

type(user_a.type)
#  🚀

user_a.type == "ADMIN"
# False

user_a.type == 2
# False

len(UserType)
# 3

if user_b.type:
    print("User is valid")
else:
    print("Not a valid user")
# User is valid

[user_type for user_type in UserType]
# [, , ]

Итак, Enum уже мощнее, чем простой класс в моделировании нашего дела . Это действительно помогает нам выразить некоторые характеристики категории/списка.

Есть пара большего количества вещей, связанных с Enums, некоторые хорошие встроенные функции.

Я могу получить доступ к Enum по-разному, используя как кронштейны и точечные обозначения:

UserType['ADMIN']
# 

UserType.ADMIN
# 

Каждый член Enum имеет ценность и Имя атрибут:

UserType.ADMIN.value
# 2

UserType.ADMIN.name
# ADMIN

Еще одна аккуратная особенность – это то, что вы не можете изменять Enum во время выполнения:

list(UserType)
# [, , ]

UserType.NOOB = 3

list(UserType)
# [, , ]

type(UserType.ADMIN) is type(UserType.MODERATOR)
# True

type(UserType.ADMIN) is type(UserType.NOOB)
# False

Как вы можете увидеть enums В Python действительно мощно, и они инкапсулируют концепции скважин, такие как категории или типы.

Документация Python Хорошо и тщательно охватывает все детали, я бы порекомендовал проверить это.

Полезные ресурсы

  1. Константы Python

Оригинал: “https://dev.to/barrachri/why-you-need-enums-and-how-to-use-them-in-python-4nf2”