2012-10-10 71 views
10

Ha habido algunas preguntas sobre cómo implementar enumeraciones en Python. La mayoría de las soluciones terminan siendo más o menos equivalente a algo como esto:Diseño pitónico sin enums

class Animal: 
    DOG=1 
    CAT=2 

Otros tienen sugerir formas más complicadas de la construcción de las enumeraciones, pero la ultimatly tienden a parecer a este ejemplo, cuando todo está dicho y hecho.

Basado en mi experiencia en Java y C#, puedo pensar en todo tipo de usos para este tipo de modismo. Sin embargo, no parece ser muy pitónico. De hecho, parece que cada vez que alguien pregunta por qué no hay enumeraciones en Python, tiendes a soltar un gruñido con respuestas enlatadas sobre cómo no hay razón para intentar aplicar la seguridad del tipo de tiempo de compilación en un lenguaje como Python. o cómo los diseños que requieren enumeraciones son malos olores en Python.

Mi pregunta no es cómo implementar enumeraciones en Python, sino cómo en general las personas abordan las soluciones a los problemas que se prestan a las enumeraciones de una manera pitonica. En otras palabras, ¿cómo resolverías un problema que se presta a tener un tipo de datos con un conjunto discreto de valores posibles sin transferir tu solución Java/C# a Python?

+2

No veo por qué el ejemplo que dio es antiétónico. Y si estuviera implementando una máquina de estado, aprovecharía que las funciones son objetos y definiría mis estados como funciones. –

+0

No sé si hay algo particularmente malo sobre cómo se implementó la enumeración, pero me da la sensación de que algunas personas en la comunidad de Python consideran que las soluciones que requieren enumeraciones en primer lugar no son pionónicas. ¡Sin embargo, su sugerencia de que una máquina de estados se implemente usando funciones de primera clase como estado es un buen comienzo para una respuesta! – jlund3

Respuesta

4

PEP 435 acaba de ser aceptado, que agrega el paquete enum a la biblioteca estándar junto con la clase Enum y otras derivadas como IntEnum. Esto significa que comenzando con Python 3.4, la forma "pitonica" de usar enumeraciones en un diseño es con este paquete.Se verá algo como esto:

>>> from enum import Enum 
>>> class Color(Enum): 
... red = 1 
... green = 2 
... blue = 3 

>>> print(Color.red) 
Color.red 

>>> print(Color.red.name) 
red 

>>>> for color in Color: 
....  print(color) 
Color.red 
Color.green 
Color.blue 

La característica clave de este diseño es que las teclas pueden rechazar la comparación en la que no tiene sentido (a diferencia de las claves de cadena que se sugieren en otras respuestas), permiten que las claves tienen la impresión bastante no relacionado con el valor clave, así como dando a los valores clave propiedades especiales definiendo métodos en la subclase Enum, además de la propiedad de arrojar un error explícito y comprensible si el usuario intenta usar una clave ilegal de la clase Enum.

+0

El único inconveniente es: no funciona antes de Python 3.4, que ya no está en una distribución importante (octubre de 2013). Así que esperemos y bebamos té. – nerdoc

+1

Un respaldo de PEP 435 para Python 2.4+ está disponible en PyPI como [enum34] (https://pypi.python.org/pypi/enum34/). Aunque no es oficial, está escrito por el coautor del PEP 435, Ethan Furman. – tawmas

1

Al no haber provenido de un C# o de un fondo Java, todavía no entiendo muy bien este interés en las enumeraciones.

Por lo que entiendo, probablemente volveré al estilo django, poniendo las constantes necesarias en un archivo de configuración e importando cuando sea necesario.

settings.py/animals.py

DOG = 1 
CAT = 2 
otra

archivo:

from animals import CAT, DOG 

o incluso ...

settings.py

ANIMALS = { "DOG": 1, "CAT": 2} 

otro archivo:

from settings import ANIMALS 

my_animal = "FROG" 
if my_animal not in ANIMALS.keys(): 
    print "new species discovered!" 
+2

'if my_animal no en ANIMALS.keys():' es en realidad (a) más largo y (b) menos eficiente, que la comprobación más simple 'if my_animal not in ANIMALS'. – Amber

+2

Creo que este ejemplo destaca por qué las personas con exposición a Java/C# quieren enums en Python. Una cosa es aceptar el tipado de patos, en el que se acepta todo lo que sepa cómo hacerlo. Es una cuestión completamente diferente (para un chico Java/C#) decir que su lenguaje permite errores de tipeo simples para atornillarlo. Por ejemplo, supongamos que escribí my_animal = "dog" en lugar de my_animal = "DOG" y de alguna manera descubrí una nueva especie. Tener una enumeración donde puedes decir my_animal = Animal.DOG te ahorra un poco de dolor ya que obtendrás un AttributeError en tu cara en tiempo de ejecución en lugar de un error de especie descubierta. – jlund3

+0

Es cierto, solo me gusta mostrar explícitamente lo que se está haciendo, ya que los recién llegados no tienen claro qué se está haciendo en la alternativa. – monkut

3

Como las cadenas de Python son inmutables (y Python ellos internos como lo considere necesario), no es realmente una ventaja específica a la utilización de las enumeraciones numéricos para los conjuntos de cosas. En su lugar, puede simplemente usar un frozenset o tuple de cadenas (dependiendo de si le importa ordenar).

Si, por otro lado, lo que le importa es el espacio de nombres, hacer que los atributos de una clase funcionen bien.

Como se mencionó en los comentarios, si está buscando algo así como una implementación de máquina de estado, las funciones de primera clase son su amiga.

+0

.. Y si te importa el espacio de nombres * y * estás usando 3.3, existe esta receta: http://code.activestate.com/recipes/578279-using-chainmap-for-embedded-namespaces/?in=lang -python –

+1

Si está utilizando 3.3, puede usar ['types.SimpleNamespace'] (http://docs.python.org/py3k/whatsnew/3.3.html#simplenamespace) :) –

-1

No creo en los Enumerados en C#. Para State-Machine tienes el patrón de Estrategia. En lugar de mirar el estado de un objeto y decidir qué hacer. Encapsule la lógica de qué hacer en el objeto mismo.

Este es un enfoque natural en Python y la introducción de enums para mí solo está fomentando el código incorrecto.

+0

La pregunta no es hablar especialmente sobre máquinas de estado. Estoy de acuerdo en que tanto en C# como en las enumeraciones de Python no son el camino a seguir para implementar una máquina de estado. Sin embargo, estamos hablando de representar un tipo que tiene un pequeño conjunto de valores con nombre que puede asumir. Para problemas que involucran ese tipo de tipo de datos, las enumeraciones son bastante útiles. – jlund3

+0

Para mí eso suena como herencia. Un tipo que tiene un pequeño conjunto de valores con nombre. Una vez más, Python lo hizo bien la primera vez al no incluir enumeraciones. –

+0

Usar la herencia para crear múltiples tipos de datos con la misma clase primaria no es lo mismo que tener un solo tipo de datos con un pequeño conjunto de valores posibles ... – jlund3