如何在每次迭代中获得Enum属性的随机值?

时间:2017-11-17 14:59:21

标签: python random lambda enums

我创建了这样的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.MALE: 'male'>
>>> Gender.RANDOM
<Gender.MALE: 'male'>
>>> Gender.RANDOM
<Gender.MALE: 'male'>
>>> Gender.RANDOM
<Gender.MALE: 'male'>

我也尝试过使用lambda,但它看起来不太好,虽然它有效:

Gender.RANDOM()

是否有其他方法可以每次获取随机值,而不使用lambda表达式?

我们使用这个枚举对象作为某个方法的参数的默认值,这个方法应该是属性而不是函数,因为当我们使用Gender.FEMALE时它不是函数,它& #39;是一个属性,Gender.RANDOM也应该是一个属性:

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


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

8 个答案:

答案 0 :(得分:11)

正如其他人所说,最好的方法是让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()

答案 1 :(得分:5)

我尝试了metaclasses的方法。它有效!

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的元类设为GenderRANDOM_ATTR类似于类Gender的对象,因此RANDOM具有property def full_name(gender=Gender.RANDOM): ...

但是,您在问题中描述的以下代码无法按预期方式运行。

RANDOM

def full_name(gender=None): gender = gender or Gender.RANDOM ... 属性只会被调用一次。要知道原因,请阅读answer。默认参数类似于函数的属性,它只会被初始化一次。

为此我建议你做这样的事情:

data() {
  return {
     ...
     req: {},
     ...
  }
}

答案 2 :(得分:3)

您可能应该在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()

答案 3 :(得分:2)

我认为你想要一个方法随机,而不是直接将值保存在变量中,因为如果这样做,值将永远不会改变:

如果你想要一个功能

随机导入 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()

外观:

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

答案 4 :(得分:2)

由于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()
    # ...

答案 5 :(得分:0)

来自文档:“枚举是一组符合唯一,常量值的符号名称(成员)。” 你需要切换到另一个类似的表示。

答案 6 :(得分:0)

虽然在很多情况下修改课程可能会更清晰,但是如果您只是这样做一次或者不想修改枚举,您可以这样做:

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

答案 7 :(得分:0)

另一个适用于您的目标的选项是:

from enum import Enum
import random

class Gender(Enum):
    MALE = object()
    FEMALE = object()

    @classmethod
    def get_random_gender(cls):
        gender = random.choice(cls._member_names_)
        return gender.lower()


print(Gender.get_random_gender())
>> female