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):
...
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
...
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()
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()
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()
# ...
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'
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.