用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__
)方法中时,并不是所有的类初始化都已完成。例如,如果PlanSerializer
的PlanSerializer
方法本身将使用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
类的用法产生延迟时实际使用它,而不是解析类的身体的时候,它应该工作。