web-dev-qa-db-fra.com

Comment obtenir une valeur aléatoire d'attribut Enum à chaque itération?

J'ai créé un tel objet Enum:

class Gender(Enum):
    FEMALE = 'female'
    MALE = 'male'
    RANDOM = random.choice([FEMALE, MALE])

et je veux obtenir une valeur vraiment aléatoire à chaque fois, mais cela ne fonctionne pas: 

>>> class Gender(Enum):
...    MALE = 'male'
...    FEMALE = 'female'
...    RANDOM = choice([MALE, FEMALE])
... 
>>> Gender.RANDOM
<Gender.MALE: 'male'>
>>> Gender.RANDOM
<Gender.MALE: 'male'>
>>> Gender.RANDOM
<Gender.MALE: 'male'>
>>> Gender.RANDOM
<Gender.MALE: 'male'>

J'ai aussi essayé d'utiliser lambda, mais ça n'a pas l'air bien, même si ça marche:

Gender.RANDOM()

Existe-t-il un autre moyen d'obtenir des valeurs aléatoires à chaque fois, sans utiliser d'expressions lambda?

Nous utilisons cet objet enum comme valeur par défaut de l'argument de la méthode some, c'est pourquoi il devrait s'agir d'un attribut, pas d'une fonction, car lorsque nous utilisons Gender.FEMALE, ce n'est pas une fonction, c'est un attribut et Gender.RANDOM devrait également l'être:

def full_name(gender=Gender.FEMALE):
    ...


def full_name(gender=Gender.RANDOM):
    ...
17
Lo L

J'ai essayé un moyen avec métaclasses . Et il fonctionne!

import random
import enum
class RANDOM_ATTR(enum.EnumMeta):
    @property
    def RANDOM(self):
        return random.choice([Gender.MALE, Gender.FEMALE])


class Gender(enum.Enum,metaclass=RANDOM_ATTR): #this syntax works for python3 only
    FEMALE = 'female'
    MALE = 'male'


print(Gender.RANDOM)   #prints male or female randomly

Ici en faisant RANDOM_ATTR la métaclasse de Gender, Gender est comme un objet de classe RANDOM_ATTR, donc Gender a la propriété propriétéRANDOM.

Toutefois, le code ci-dessous que vous avez décrit dans votre question ne fonctionne pas comme prévu.

def full_name(gender=Gender.RANDOM):
    ...

La propriété RANDOM sera appelée une seule fois. Pour savoir pourquoi, lisez ceci réponse . Les arguments par défaut sont comme des attributs à utiliser, qui ne seront initialisés qu'une fois.

Pour cela, je vous suggère de faire quelque chose comme ceci:

def full_name(gender=None):
    gender = gender or Gender.RANDOM
    ...
5
Abhijith Asokan

Comme d'autres l'ont déjà dit, le meilleur moyen consiste simplement à faire de random() une méthode de votre classe enum afin de préciser que RANDOM n'est pas un membre.

Cependant, depuis que j'aime les énigmes:

from enum import Enum
import random

class enumproperty(object):
    "like property, but on an enum class"

    def __init__(self, fget):
        self.fget = fget

    def __get__(self, instance, ownerclass=None):
        if ownerclass is None:
            ownerclass = instance.__class__
        return self.fget(ownerclass)

    def __set__(self, instance, value):
        raise AttributeError("can't set pseudo-member %r" % self.name)

    def __delete__(self, instance):
        raise AttributeError("can't delete pseudo-member %r" % self.name)

class Gender(Enum):
    FEMALE = 'female'
    MALE = 'male'
    @enumproperty
    def RANDOM(cls):
        return random.choice(list(cls.__members__.values()))

L'utilisation de cette valeur par défaut dans une définition de fonction ne vous donnera pas ce que vous voulez. La méthode standard pour cela est:

def full_name(gender=None):
    if gender is None:
        gender = Gender.RANDOM

Ce qui va être déroutant pour le lecteur. C'est beaucoup mieux en utilisant une méthode normale:

def full_name(gender=None):
    if gender is None:
        gender = Gender.random()
11
Ethan Furman

Vous devriez probablement créer une méthode dans votre Enum pour obtenir un genre aléatoire:

import random
import enum

class Gender(enum.Enum):
    FEMALE = 'female'
    MALE = 'male'

    @classmethod
    def get_gender(cls):
        return random.choice([Gender.FEMALE, Gender.MALE])

Gender.get_gender()
3
Reblochon Masque

Comme RANDOM n'est pas vraiment un élément de votre énumération, je pense qu'une approche plus cohérente consisterait à le conserver précisément comme méthode et pas à un attribut (ce n'est pas du tout!).

import random
import enum


class Gender(enum.Enum):
    MALE = 'male'
    FEMALE = 'female'

    @staticmethod
    def random():
        return random.choice(list(Gender))

Ensuite, vous pouvez transférer le comportement "je ne choisis pas" à la fonction où il a plus de sens.

def full_name(gender=None):
    if gender is None:
        gender = Gender.random()
    # ...
2
grovina

Je pense que vous voulez une méthode aléatoire, au lieu de sauvegarder la valeur directement dans la variable, car si vous faites cela, la valeur ne changera jamais:

Si vous ne voulez pas une fonction

import aléatoire import enum

class Gender(enum.Enum):

  MALE = 'male'
  FEMALE = 'female'
  RANDOM = random.choice([MALE, FEMALE])


  def __getattribute__(self,item):
    if item == "RANDOM":
      Gender.RANDOM = random.choice([self.MALE, self.FEMALE])
      return Gender.RANDOM
    else:
      return object.__getattribute__(self, item)

gender = Gender()

regardez:

   gender.RANDOM
=> 'female'
   gender.RANDOM
=> 'male'
   gender.RANDOM
=> 'male'
   gender.RANDOM
=> 'male'
   gender.RANDOM
=> 'female'
   gender.RANDOM
=> 'male'
   gender.RANDOM
=> 'male'
   gender.RANDOM
=> 'female'
2
Damian Lattenero

Dans la documentation: "Une énumération est un ensemble de noms symboliques (membres) liés à des valeurs uniques constant." Vous devez passer à une autre représentation, telle qu'une classe.

0
LeGBT