9
votes

CLASSE PYTHON ENUM (avec TOSTRING DUBING)

J'ai trouvé un moyen simplement de mettre en œuvre (pirater) un énumé dans Python: xxx

i peut ensuite appeler ceci comme tel: xxx

sexy!

D'accord, je veux maintenant pouvoir obtenir la valeur numérique si elle est donnée une chaîne ou une chaîne si elle est donnée une valeur numérique. Disons que je veux que les chaînes correspondent exactement à la clé Enum's

Le meilleur que je puisse penser est quelque chose comme ceci: xxx

ou quelque chose comme que (ignorer comment j'attrape des cas invalides)

existe-t-il une meilleure façon de faire une meilleure façon de faire ce que je fais au-dessus? Ou ce qui précède est-il déjà aussi concis que possible.

Il semble qu'il y ait une meilleure façon de le faire.


3 commentaires

Ce montant de si / sinon indique toujours que c'est une solution incorrecte;)


duplicaillier possible de Quel est le meilleur moyen de mettre en œuvre un "Enum 'en python?


@Nick: Vous voudrez peut-être changer votre réponse acceptée.


7 Réponses :


1
votes

Vous pouvez utiliser des dictionnaires:

class MyEnum:
    VAL1, VAL2, VAL3 = range(3)
    __toString = { VAL1 : "VAL1", VAL2 : "VAL2", VAL3 : "VAL3" }

    @classmethod
    def tostring(cls, val):
        return cls.__toString.get(val)

    @classmethod
    def fromstring(cls, str):
        i = str.upper()
        for k,v in cls.__toString.iteritems():
            if v == i:
                return k
        return None


print MyEnum.tostring(MyEnum.VAL1)
print MyEnum.fromstring("VAL1")


2 commentaires

Les doubles traits de soulignement (= Nom Mangling) sont ... Eh bien, pas mal, mais je n'ai jamais vu ce cas hypothétique où ils ont un petit avantage, par opposition à l'utilisation d'un cas habituel où ils pausent des choses.


@delnan. Je vais prendre note de cela.



12
votes

Eh bien, voici ce que vous avez demandé:

class MyEnum:
  VAL1, VAL2, VAL3 = range(3)
  @classmethod
  def tostring(cls, val):
    for k,v in vars(cls).iteritems():
        if v==val:
            return k

  @classmethod
  def fromstring(cls, str):
      return getattr(cls, str.upper(), None)

print MyEnum.fromstring('Val1')
print MyEnum.tostring(2)


11 commentaires

Myenum.tostring (3) ne renvoie aucun. Je devrais probablement être myenum.tostring (myenum.val3)


C'est parce que plage commence à 0. tostring (2) donne val3 . Noms malheureux ( * [1-9] ). AFAIK, C / C ++ Enum commence à 0 aussi.


@delnan vrai. J'étais confus d'un test que j'ai fait de mon côté. Probablement un effet secondaire qui m'a empêché d'utiliser un INT directement dans la méthode de totrage.


"Tostring" et "FromsRing" sont certainement javesque. Python n'a pas besoin de ce cruft.


Je pense qu'un attributeError doit être soulevé dans itstring () quand il n'y a pas d'attribut avec le nom propre au lieu de renvoyer Aucun .


Pas une bonne idée donne des noms de variables qui conflit avec intégré - comme vous l'avez fait avec str .


@Martineau: Comme je l'ai dit, c'est ce que l'op a demandé pour. Je voulais juste montrer comment utiliser les fonctionnalités dynamiques de Python pour raccourcir son code, rien de plus. @Nick: Je ne peux pas voir Enums comme une bonne idée de Python, alors n'écrivez pas l'énumé parfaite pour vous, mais vous devez suivre les commentaires de Martineau si vous souhaitez utiliser cela.


@ THC4K: En fait, ce que l'OP a demandé était "Y a-t-il une meilleure façon centrée sur le point de faire ce que je fais)" et dit "(ignorer comment j'atteignons les cas invalides)" sur son code d'échantillon.


Si les énumérums ne sont d'aucune utilité dans Python, c'est étrange comment tant de gens ont ressenti le besoin de mettre en œuvre quelque chose comme eux au fil des ans. Une façon dont je les utilise personnellement est de donner des noms comme des nombres magiques et de rendre mes scripts plus descriptifs et lisibles.


Non seulement c'est étrange combien de personnes ont ressenti le besoin de les mettre en œuvre; Ils ont en quelque sorte fini dans la bibliothèque standard! Clairement, il y a beaucoup d'utilité pour eux.


Je ne sais pas pourquoi @jsbueno commentaire est uplifié ici. C'est la situation et certainement pas cruft. Toujours essayer d'adapter le bon outil pour la bonne situation et méfiez-vous des programmeurs qui soutiennent que la seule façon est la vraie façon.



7
votes

Utilisez un dict:

MyEnum['VAL4'] = 4


2 commentaires

Si je dois construire un 2e dictionnaire pour aller dans l'autre sens, cela viole la valeur de la définition unique préférée dans n'importe quelle langue. Comment répondez-vous à cette préoccupation?


L'extensibilité n'est pas une fonctionnalité pour Enums.




0
votes

Vous ne devez pas avoir à coder vos valeurs dans la classe - vous feriez mieux d'avoir une usine d'énumérateur. Alors qu'à cela, il suffit d'ajouter des Nicetieurs fournis par Python, par exemple, remplacer la méthode de représentation ou l'attribut GET:

>>> enum = Enumerator("val1", "val2", "val3")
>>> enum
['val3', 'val2', 'val1']
>>> enum.val2
1
>>> enum["val1"]
0
>>> enum[2]
'val3'


0 commentaires

3
votes

Cela fera ce que vous voulez et générera votre implémentation légèrement réduisant le code de la plaque de chaudière: xxx


0 commentaires

22
votes

[Time passe ...]

Le nouveau Python Enum a enfin atterri en 3.4, et a Également été rééquilibré . La réponse à votre question est donc maintenant à utiliser cela. :)


Exemple: xxx


0 commentaires