简体   繁体   English

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

[英]In Python, how to initialize a class attribute from the return value of a class method?

Imagine we have this class: 想象一下,我们有这个课程:

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

    mapping = {"key": ... }

I would like to associate the value returned by get_choices() to key . 我想将get_choices()返回的值与key相关联。 What code should go instead of the placeholder ... ? 应该使用什么代码而不是占位符...


EDIT: I wanted to keep the question context-agnostic (it seemed to me that this requirement was common enough, but I could be biased). 编辑:我想保持与上下文无关的问题(在我看来,这个要求很常见,但我可能有偏见)。 As was suggested in comments, I will give some more details, because it seems we share the concern of 'most straightforward code': 正如评论中所建议的那样,我将提供更多细节,因为我们似乎共同关注“最简单的代码”:

I am working on a Django application, where I want to keep enumeration of values separated of the Model s using them. 我正在开发一个Django应用程序,我希望使用它们来保持Model的值的枚举 What seemed to me like a natural solution was to create an enumeration.py module, where I could then define a class for each enumeration (the class having at least a class method to generate the collection of values). 在我看来,像一个自然的解决方案是创建一个enumeration.py模块,然后我可以为每个枚举定义一个class (该类至少有一个类方法来生成值集合)。 This is the get_choices() in the example. 这是示例中的get_choices()

Now, because of business logic, I need to map those choices to a key. 现在,由于业务逻辑,我需要将这些选择映射到密钥。 This mapping being logically coupled to the enumeration, it seemed like a good structure to keep them together, in the same class (giving client code uniform and explicit access, being prefixed by the class name). 这个映射在逻辑上耦合到枚举,在同一个类中保持它们在一起似乎是一个很好的结构(给客户端代码统一和显式访问,以类名为前缀)。

You cannot do it in class definition because class object has not been created yet. 您无法在类定义中执行此操作,因为尚未创建类对象。 After the class definition, you could definitely do something like this - 在课程定义之后,你绝对可以做到这样的事情 -

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

Although the recommended way to do this would be to use a metaclass. 虽然推荐的方法是使用元类。

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

With that said, that is an Object Oriented solution to the problem. 话虽如此,这是一个面向对象的问题解决方案。 you can ofcourse use some function to generate choices thus ending the need to use metaclass. 您可以使用某些函数来生成选择,从而结束使用元类的需要。

For Edited Question:- 编辑问题: -

In that case, I think you should just maintain a file named 'choices.py' as you yourself suggested and use them in your mapping, instead of get_choices class method. 在这种情况下,我认为您应该按照自己的建议维护一个名为“choices.py”的文件,并在映射中使用它们,而不是使用get_choices类方法。 You don't need to unnecessarily make classes for each model if all you want to do is store choices. 如果你想做的只是商店选择,你不需要为每个模型不必要地创建类。 Just use dicts and constants. 只需使用dicts和常量。

If your classes needs to be generated dynamically, say from db, then you need to create separate model for storing choices. 如果你的类需要动态生成,比如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
     }

This is just a raw design, might need to be improved a lot, but something on these lines. 这只是一个原始设计,可能需要进行很多改进,但在这些方面有所改进。

If the logic you need to run is trivial then just putting the logic directly after the class is fine: 如果您需要运行的逻辑是微不足道的,那么只需在类之后直接放置逻辑:

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

If the logic is more complicated, and especially if needed by multiple classes, then a decorator could be useful. 如果逻辑更复杂,特别是如果需要多个类,则装饰器可能很有用。 eg 例如

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]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM