用Python元类中的类添加动态属性

问题描述:

我使用mongoengine和Django rest框架。我的模型:用Python元类中的类添加动态属性

import mongoengine as mongo 
class Plan(mongo.Document): 
    slug = mongo.StringField(max_length=255, primary_key=True) 
    subplans = mongo.ListField(mongo.EmbeddedDocumentField('self')) 

我需要序列化程序是这个样子的:

class PlanSerializer(serializers.DocumentSerializer): 
    subplans = PlanSerializer(many=True, required=False) 

    class Meta: 
     model = Plan 

但是,不正确的Python。所以我用了元类动态地添加subplans领域:

class AddSubplanAttrMetaclass(type): 
    def __new__(cls, name, bases, dct): 
     # this code is incorrect because PlanSerializer not in globals 
     class_obj = globals()[name] 
     dct['subplans'] = class_obj(many=True, required=False) 
     return super(AddSubplanAttrMetaclass, cls).__new__(cls, name, bases, dct) 

class PlanSerializer(serializers.DocumentSerializer, metaclass=AddSubplanAttrMetaclass): 

    class Meta: 
     model = Plan 

如何设置PlanSerializer类物业内的元类__new__方法?

你有,当你尝试要么使用线 subplans = PlanSerializer(many=True, required=False)并与元类尝试时,该行class_obj = globals()[name]当你PlanSerializerclass本身没有定义的问题。 (检查我的答案在How is super() in Python 3 implemented?

正确的方法做,在元类将是调用父类的新的第一 - 返回你实际的类对象,然后调用该对象 - 沿东西:

class AddSubplanAttrMetaclass(type): 
    def __new__(metacls, name, bases, dct): 
     # this code is incorrect because PlanSerializer not in globals 
     class_obj = super(AddSubplanAttrMetaclass, cls).__new__(metacls, name, bases, dct) 
     class_obj.subplans = class_obj(many=True, required=False) 
     return class_obj 

但是这两个都不需要,并且可能仍然存在问题 - 因为当您仍处于元类的__new__(或甚至__init__)方法中时,并不是所有的类初始化都已完成。例如,如果PlanSerializerPlanSerializer方法本身将使用super,则该调用将失败 - super只能在完成类的初始化后使用。

但是,您根本不需要元类 - 您可能可以简单地将subplans属性设置为描述符 - 并且可以懒惰地检索属性。

class PlanSerializer(serializers.DocumentSerializer): 
    class Meta: 
     model = Plan 

PlanSerializer.subplans = PlanSerializer(many=True, required=False) 

我大概说因为如果蒙戈需要的属性被设置初始化类本身时,这是不行的 - 如果是这样的话,你可以尝试诉诸描述符对象。描述符只是一个实现方法的对象,如下所示。通常通过@property装饰器完成,但这对于这种情况下所需的类级别属性不起作用。

class PlanSerializer(serializers.DocumentSerializer): 
    class Subplans(object): 
     serializer = None 
     def __get__(self, instance, owner): 
      if not self.serializer: 
       self.serializer = PlanSerializer(many=True, required=False) 
      return self.serializer 
    subplans = Subplans() 

    class Meta: 
     model = Plan 

以这种方式在调用Subplans类的用法产生延迟时实际使用它,而不是解析类的身体的时候,它应该工作。