我创建了这样的Enum对象:
class Gender(Enum):
FEMALE = 'female'
MALE = 'male'
RANDOM = random.choice([FEMALE, MALE])
我想每次都得到真正的随机值,但它不起作用:
>>> class Gender(Enum):
... MALE = 'male'
... FEMALE = 'female'
... RANDOM = choice([MALE, FEMALE])
...
>>> Gender.RANDOM
>>> Gender.RANDOM
>>> Gender.RANDOM
>>> Gender.RANDOM
我也尝试过使用lambda,但是它看起来不太好,尽管它可以工作:
Gender.RANDOM()
是否有其他方法可以在不使用lambda表达式的情况下每次获取随机值?
我们使用这个枚举对象作为某个方法的参数的默认值,这就是为什么它应该是一个属性而不是一个函数,因为当我们使用Gender.FEMALE时,它不是一个函数,它是一个属性,Gender.RANDOM也应该是一个属性:
def full_name(gender=Gender.FEMALE):
...
def full_name(gender=Gender.RANDOM):
...
默认属性只计算一次(当您定义函数时),因此随机值将只随机一次,每次调用该函数时,您将获得相同的初始值。
这是我想要改变的惯常行为。
这是Python的基本行为,您不能更改它。
我指的是权宜之计。当然,我不能更改python,我不想这样做。
什么解决方法?def full_name(gender=Gender.RANDOM):不是一个解决方法。
@Ethanfurman我实际上可以用这个答案中的描述符classproperty来实现,但我希望有一个更简单的解决方案,那就是用大量的Python。
强制性XKCD
正如其他人所说,最好的方法就是让random()成为枚举类上的一个方法,以清楚地表明RANDOM不是成员。
但是,因为我喜欢拼图:
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()))
在函数定义中将此值用作默认值不会得到您想要的结果。标准方法是:
def full_name(gender=None):
if gender is None:
gender = Gender.RANDOM
这会让读者感到困惑。使用普通方法更好:
def full_name(gender=None):
if gender is None:
gender = Gender.random()
你是对的。它比使用gender.random作为默认值要清楚得多。谢谢!
我尝试了一种使用元类的方法。它工作!
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
在这里,通过使RANDOM_ATTR成为Gender的元类,Gender就像是RANDOM_ATTR的对象,所以Gender拥有RANDOM的属性。
但是,您在问题中描述的下面的代码并不像您期望的那样工作。
def full_name(gender=Gender.RANDOM):
...
RANDOM属性只能调用一次。要知道原因,请阅读此答案。默认参数类似于函数的属性,只初始化一次。
为此,我建议你做如下的事情:
def full_name(gender=None):
gender = gender or Gender.RANDOM
...
@伊桑弗曼,我确认。它对我不起作用。
@堆栈队列现在工作正常!
干得真不错…我一直在努力,并能得到这个结果,这是我朋友的一个优点。
你可能应该在你的Enum中创建一个方法来获得一个随机的性别:
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()
我们使用这个枚举对象作为某些方法的默认值,它应该是Gender.RANDOM,而不是Gender.get_random()或Gender.RANDOM()。这是为了清晰的API。
是的,classmethod正是我想要的,谢谢你指出
由于RANDOM在您的枚举中并不是一个真正的项,所以我认为一种更为一致的方法是将它精确地保持为一个方法而不是一个属性(它毕竟不是!).
import random
import enum
class Gender(enum.Enum):
MALE = 'male'
FEMALE = 'female'
@staticmethod
def random():
return random.choice(list(Gender))
然后,你可以把"我没有选择"的行为转移到函数中,它实际上更合理。
def full_name(gender=None):
if gender is None:
gender = Gender.random()
# ...
我认为您需要一个随机方法,而不是直接将值保存在变量中,因为如果这样做,值将永远不会改变:
如果你不想要一个函数
随机进口导入枚举
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()
看:
gender.RANDOM
=> 'female'
gender.RANDOM
=> 'male'
gender.RANDOM
=> 'male'
gender.RANDOM
=> 'male'
gender.RANDOM
=> 'female'
gender.RANDOM
=> 'male'
gender.RANDOM
=> 'male'
gender.RANDOM
=> 'female'
我试过了,这很有效,但是大写的方法看起来很难看。
@我知道它看起来很难看。我只是按照你的例子,显然你可以用你想要的名字
@LKRI,看,我改变了它,即使每次你调用随机方法,你都把它存储在随机变量中。
使用classmethod时,您的RANDOM签名应为def RANDOM(cls): and your line can merandom=random.choice(list(cls))。`
@现在我明白你的问题了
@Ethanfurman忘记了类方法,我误解了这个问题。
你以前的回答更好。;)__getattribute__很容易出错,对于这样一个简单的问题来说,杀伤力太大。
尽管在许多情况下修改类可能更清晰、更干燥,但如果您只进行一次修改或不想修改枚举,则可以执行以下操作:
random.choice([enm.value for enm in Gender])
来自文档:"枚举是一组符号名(成员),绑定到唯一的常量值。"您需要像类一样切换到另一个表示。
为什么?保留Enum有其优点,特别是使用Gender的类型。
嗯,我认为,Python式的方法只不过是做一个能让一个随机性别返回到枚举之外的动作…
使用Enum是可以的。使用RANDOM作为一个非常量是不可能的。