python random lambda enums

python - ¿Cómo obtener el valor aleatorio del atributo de Enum en cada iteración?



random lambda (7)

He creado tal objeto Enum :

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

y quiero obtener un valor realmente aleatorio cada vez, pero no funciona:

>>> 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''>

También he intentado usar lambda, pero no se ve tan bien, aunque funciona:

Gender.RANDOM()

¿Hay otra forma de obtener valores aleatorios cada vez, sin utilizar expresiones lambda?

Usamos este objeto enum como valor predeterminado del argumento de algún método, por eso debería ser un atributo, no una función, porque cuando usamos Gender.FEMALE no es una función, es un atributo y Gender.RANDOM debería ser un atributo también:

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


Aunque la modificación de la clase puede ser más clara y DRY-er en muchos casos, si solo haces esto una vez o no quieres modificar la enumeración, puedes hacerlo:

random.choice([enm.value for enm in Gender])


Como RANDOM no es realmente un elemento en su enumeración, creo que un enfoque más coherente sería mantenerlo precisamente como un método y no como un atributo (¡no lo es después de todo!).

import random import enum class Gender(enum.Enum): MALE = ''male'' FEMALE = ''female'' @staticmethod def random(): return random.choice(list(Gender))

Luego, podría transferir el comportamiento "No estoy eligiendo" a la función en la que realmente tiene más sentido.

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


Como han dicho otros, la mejor manera es simplemente hacer que random() sea ​​un método en su clase de enumeración para dejar en claro que RANDOM no es un miembro.

Sin embargo, como me gustan los puzzles:

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()))

Si utiliza esto como un valor predeterminado en una definición de función, no obtendrá lo que desea. El método estándar para tal es:

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

Lo que va a ser confuso para el lector. Esto es mucho mejor usando un método normal:

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


Creo que quieres un método aleatorio, en lugar de guardar el valor directamente en la variable, porque si lo haces, el valor nunca cambiará:

Si no quieres una funcion

importar enum de importación aleatoria

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()

Mira:

gender.RANDOM => ''female'' gender.RANDOM => ''male'' gender.RANDOM => ''male'' gender.RANDOM => ''male'' gender.RANDOM => ''female'' gender.RANDOM => ''male'' gender.RANDOM => ''male'' gender.RANDOM => ''female''


De la documentación: "Una enumeración es un conjunto de nombres simbólicos (miembros) vinculados a valores únicos y constantes ". Necesitas cambiar a otra representación como una clase.


Probé un camino con metaclasses . ¡Y funciona!

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

Aquí, al hacer de RANDOM_ATTR la metaclase del Gender , Gender es como un objeto de la clase RANDOM_ATTR , por lo que Gender tiene la property RANDOM .

Sin embargo, el siguiente código que describió en su pregunta no funciona como esperaba.

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

La propiedad RANDOM será llamada una sola vez. Para saber por qué, por favor lea esta answer . Los argumentos predeterminados son como atributos para funcionar, que se inicializarán solo una vez.

Para eso te sugiero que hagas algo como esto:

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


Probablemente debería crear un método en su Enum para obtener un género aleatorio:

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()