在Python中,如何从类方法的返回值初始化类属性?

时间:2015-08-19 09:18:10

标签: python class python-3.x

想象一下,我们有这个课程:

class Custom:
    @classmethod
    def get_choices(cls):
        # use cls attributes to return a list

    mapping = {"key": ... }

我想将get_choices()返回的值与key相关联。应该使用哪些代码而不是占位符...

编辑:我想保持与上下文无关的问题(在我看来,这个要求很常见,但我可能有偏见)。正如评论中所建议的那样,我将提供更多细节,因为我们似乎共同关注“最直接的代码”:

我正在开发一个Django应用程序,我希望将枚举的值分隔为Model s。在我看来,像一个自然的解决方案是创建一个 enumeration.py 模块,然后我可以为每个枚举定义一个class(该类至少具有一个类方法生成值集合)。这是示例中的get_choices()

现在,由于业务逻辑,我需要将这些选择映射到一个键。这个映射在逻辑上耦合到枚举,在同一个类中保持它们在一起似乎是一个很好的结构(给客户端代码统一和显式访问,以类名为前缀)。

2 个答案:

答案 0 :(得分:6)

您无法在类定义中执行此操作,因为尚未创建类对象。 在课程定义之后,你绝对可以做到这样的事情 -

Custom.mapping['key'] = Custom.get_choices()

虽然推荐的方法是使用元类。

class CustomMetaClass(type):

      def __init__(cls, classname, bases, attrs):
          super(CustomMetaClass, cls).__init__(classname, bases, attrs)

          cls.mapping['key'] = cls.get_choices()

class Custom(metaclass = CustomMetaClass): # assuming you are using python 3

      mapping = {}

      @classmethod
      def get_choices(cls):
          # add your custom code here
          pass

据说,这是一个面向对象的问题解决方案。你可以使用一些函数来产生选择,从而结束使用元类的需要。

编辑问题: -

在这种情况下,我认为你应该维护一个名为' choices.py'正如您自己建议并在映射中使用它们而不是get_choices类方法。如果你想做的只是商店选择,你不需要为每个模型不必要地制作课程。只需使用dicts和常量。

如果你的类需要动态生成,比如db,那么你需要创建单独的模型来存储选择。

class CustomModelChoices(models.Model):

      model_name = models.StringField(db_field = 'mn')
      choices = models.DictField(db_field = 'ch')

class CustomModel(models.Model):

     _choice_generator = CustomModelChoices

     mapping = {
         'key': CustomModelChoices.objects.get(model_name = 'CustomModel').choices
     }

这只是一个原始设计,可能需要进行大量改进,但这些方面还有一些东西。

答案 1 :(得分:0)

如果您需要运行的逻辑是微不足道的,那么只需在类完成后直接放置逻辑:

class Custom1:
    value = 1
    @classmethod
    def get_choices(cls):
        return [cls.value]
Custom1.mapping = {"key": Custom1.get_choices()}

如果逻辑更复杂,特别是如果需要多个类,则装饰器可能很有用。例如

def add_mapping_choices(cls):
    cls.mapping = {"key": cls.get_choices()}
    return cls

@add_mapping_choices
class Custom2:
    value = 2
    @classmethod
    def get_choices(cls):
        return [cls.value]