Aliases Python Enum e decorador @enum.unique

Resumo : neste tutorial, você aprenderá sobre aliases de membros de enumeração e como usar o decorador exclusivo enum para garantir a exclusividade dos valores dos membros.

Introdução aos aliases enum

Por definição, os valores dos membros de enumeração são exclusivos. No entanto, você pode criar nomes de membros diferentes com os mesmos valores.

Por exemplo, o seguinte define a Colorenumeração:

from enum import Enum


class Color(Enum):
    RED = 1
    CRIMSON = 1
    SALMON = 1
    GREEN = 2
    BLUE = 3Linguagem de código:  Python  ( python )

Neste exemplo, a Colorenumeração tem os membros RED, CRIMSONe SALMONcom o mesmo valor 1.

Quando você define vários membros em uma enumeração com os mesmos valores, o Python não cria membros diferentes, mas aliases.

Neste exemplo, the REDé o membro principal, enquanto os membros CRIMSONe SALMONsão os apelidos do REDmembro

As declarações a seguir retornam Trueporque CRIMSONe SALMONos membros são membros do RED:

print(Color.RED is Color.CRIMSON)
print(Color.RED is Color.SALMON)Linguagem de código:  Python  ( python )

Saída:

True
TrueLinguagem de código:  Python  ( python )

Ao procurar um membro por valor, você sempre obterá o membro principal, não os aliases. Por exemplo, a instrução a seguir retorna o REDmembro:

print(Color(1))Linguagem de código:  Python  ( python )

Saída:

Color.REDLinguagem de código:  Python  ( python )

Ao iterar os membros de uma enumeração com aliases, você obterá apenas os membros principais, não os aliases. Por exemplo:

for color in Color:
    print(color)Linguagem de código:  Python  ( python )

Ele retorna apenas três membros:

Color.RED
Color.GREEN
Color.BLUELinguagem de código:  Python  ( python )

Para obter todos os membros incluindo aliases, você precisa usar a __member__propriedade da classe de enumeração. Por exemplo:

from enum import Enum
from pprint import pprint


class Color(Enum):
    RED = 1
    CRIMSON = 1
    SALMON = 1
    GREEN = 2
    BLUE = 3


pprint(Color.__members__)Linguagem de código:  Python  ( python )

Saída:

mappingproxy({'BLUE': <Color.BLUE: 3>,
              'CRIMSON': <Color.RED: 1>,
              'GREEN': <Color.GREEN: 2>,
              'RED': <Color.RED: 1>,
              'SALMON': <Color.RED: 1>})Linguagem de código:  Python  ( python )

Conforme mostrado claramente na saída, e CRIMSONfazem SALMONreferência ao mesmo objeto que é referenciado pelo REDmembro:

<Color.RED: 1>Linguagem de código:  Python  ( python )

Quando usar aliases enum

Os aliases de enumeração podem ser úteis em algumas situações. Por exemplo, suponha que você precise lidar com APIs de dois sistemas diferentes. E cada sistema tem um status de resposta diferente com o mesmo significado mostrado na tabela a seguir:

Sistema 1 Sistema 2 Significado
SOLICITANDO PENDENTE A solicitação está em andamento
OK REALIZADA A solicitação foi concluída com sucesso
NÃO ESTÁ TUDO BEM REJEITADO A solicitação falhou

Para padronizar os códigos de status desses sistemas, você pode usar aliases de enumeração da seguinte maneira:

Seu sistema Sistema 1 Sistema 2 Significado
EM ANDAMENTO SOLICITANDO PENDENTE A solicitação está em andamento
SUCESSO OK REALIZADA A solicitação foi concluída com sucesso
ERRO NÃO ESTÁ TUDO BEM REJEITADO A solicitação falhou

O seguinte define a ResponseStatusenumeração com aliases:

from enum import Enum


class ResponseStatus(Enum):
    # in progress
    IN_PROGRESS = 1
    REQUESTING = 1
    PENDING = 1

    # success
    SUCCESS = 2
    OK = 2
    FULFILLED = 2

    # error
    ERROR = 3
    NOT_OK = 3
    REJECTED = 3Linguagem de código:  Python  ( python )

A seguir, comparamos o código de resposta do sistema 1 para verificar se a solicitação foi bem-sucedida ou não:

code = 'OK'
if ResponseStatus[code] is ResponseStatus.SUCCESS:
    print('The request completed successfully')Linguagem de código:  Python  ( python )

Saída:

The request completed successfullyLinguagem de código:  Python  ( python )

Da mesma forma, você pode verificar o código de resposta do sistema 2 para ver se a solicitação foi bem-sucedida:

code = 'FULFILLED'
if ResponseStatus[code] is ResponseStatus.SUCCESS:
    print('The request completed successfully')Linguagem de código:  Python  ( python )

Saída:

print('The request completed successfully')Linguagem de código:  Python  ( python )

@enum.decorador exclusivo

Para definir uma enumeração sem aliases, você pode usar cuidadosamente valores exclusivos para os membros. Por exemplo:

from enum import Enum


class Day(Enum):
    MON = 'Monday'
    TUE = 'Tuesday'
    WED = 'Wednesday'
    THU = 'Thursday'
    FRI = 'Friday'
    SAT = 'Saturday'
    SUN = 'Sunday'Linguagem de código:  Python  ( python )

Mas você pode acidentalmente usar os mesmos valores para dois membros assim:

class Day(Enum):
    MON = 'Monday'
    TUE = 'Monday'
    WED = 'Wednesday'
    THU = 'Thursday'
    FRI = 'Friday'
    SAT = 'Saturday'
    SUN = 'Sunday'Linguagem de código:  Python  ( python )

Neste exemplo, o TUEmembro é o alias do MONmembro, o que você pode não esperar.

Para garantir que uma enumeração não tenha alias, você pode usar o @enum.uniquedecorador do enummódulo.

Quando você decora uma enumeração com o @enum.uniquedecorador, o Python lançará uma exceção se a enumeração tiver aliases.

Por exemplo, o seguinte irá gerar um ValueError:

import enum

from enum import Enum


@enum.unique
class Day(Enum):
    MON = 'Monday'
    TUE = 'Monday'
    WED = 'Wednesday'
    THU = 'Thursday'
    FRI = 'Friday'
    SAT = 'Saturday'
    SUN = 'Sunday'Linguagem de código:  Python  ( python )

Erro:

ValueError: duplicate values found in <enum 'Day'>: TUE -> MONLinguagem de código:  Python  ( python )

Resumo

  • Quando uma enumeração possui membros diferentes com os mesmos valores, o primeiro membro é o membro principal, enquanto os outros são apelidos do membro principal.
  • Use o @enum.uniquedecorador do enummódulo para impor a exclusividade dos valores dos membros.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *