How to get random value of attribute of Enum on each iteration?
As others have said, the best way is to just make random()
be a method on your enum class to make it clear that RANDOM
is not a member.
However, since I like 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()))
In your full_name
definition, using Gender.RANDOM
as a default value will not get you what you want. The standard for such is:
def full_name(gender=None):
if gender is None:
gender = Gender.RANDOM # we get `MALE` or `FEMALE`, not `RANDOM`
Which is going to be confusing to the reader. This is much better using a normal method:
def full_name(gender=None):
if gender is None:
gender = Gender.random()
You probably should create a method in your Enum
to obtain a random gender:
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()
I tried a way with metaclasses. And it works!
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
Here by making RANDOM_ATTR
the metaclass of Gender
, Gender
is like an object of class RANDOM_ATTR
, so Gender
has the property RANDOM
.
However,the below code you described in your question doesn't work the way you expect.
def full_name(gender=Gender.RANDOM):
...
The RANDOM
property will be called only once. To know why, please read this answer. Default arguments are like attributes to function, which will be initialised only once.
For that i would suggest you do something like this:
def full_name(gender=None):
gender = gender or Gender.RANDOM
...