棉花糖模式和 Class 继承
Marshmallow Schema and Class Inheritance
我是第一次使用 Marshmallow,很遗憾在互联网上找不到答案。
有两个类,一个继承另一个。
两者都应该是可序列化和可反序列化的。
反序列化后,它们应该作为 Python 对象再次可用。
因此我使用 post_load
装饰器。
但似乎这会导致问题。
在下面的最小工作示例中,我得到以下异常:type object argument after ** must be a mapping, not Bicycle
.
现在可以查找属性 amount_of_tires
并在必要时传递数据。
但这似乎不是正确的解决方案。
是否有解决此问题的最佳实践?
from marshmallow import Schema, fields
from marshmallow.decorators import post_load
class Vehicle:
def __init__(self, weight):
self.weight = weight
class VehicleSchema(Schema):
weight = fields.Float()
@post_load
def make_vehicle(self, data, **kwargs) -> Vehicle:
return Vehicle(**data)
class Bicycle(Vehicle):
def __init__(self, weight, amount_of_tires):
Vehicle.__init__(self, weight=weight)
self.amount_of_tires = amount_of_tires
class BicycleSchema(VehicleSchema):
amount_of_tires = fields.Integer()
@post_load
def make_bicycle(self, data, **kwargs) -> Bicycle:
return Bicycle(**data)
my_bicycle = Bicycle(weight=10, amount_of_tires=2)
schema = BicycleSchema()
json_string = schema.dumps(my_bicycle)
deserialised_my_bicycle = schema.loads(json_string)
print(deserialised_my_bicycle)
make_vehicle
和 make_bicycle
都注册为 post_load
钩子,因此它们被一个接一个地调用。当 make_vehicle
被调用时,make_bicycle
已经被调用,所以 type(data) == Bicycle
,因此你看到的错误。
我推荐以下解决方案:
class VehicleSchema(Schema):
model_class = Vehicle
weight = fields.Float()
@post_load
def make_vehicle(self, data, **kwargs) -> Vehicle:
return type(self).model_class(**data)
class BicycleSchema(VehicleSchema):
model_class = Bicycle
amount_of_tires = fields.Integer()
要使用此解决方案获得更准确的类型提示 - 可以在基础 VehicleSchema
class 上使用 Generic
和 TypeVar
(请参阅 https://docs.python.org/3/library/typing.html#typing.Generic) .
我是第一次使用 Marshmallow,很遗憾在互联网上找不到答案。
有两个类,一个继承另一个。
两者都应该是可序列化和可反序列化的。
反序列化后,它们应该作为 Python 对象再次可用。
因此我使用 post_load
装饰器。
但似乎这会导致问题。
在下面的最小工作示例中,我得到以下异常:type object argument after ** must be a mapping, not Bicycle
.
现在可以查找属性 amount_of_tires
并在必要时传递数据。
但这似乎不是正确的解决方案。
是否有解决此问题的最佳实践?
from marshmallow import Schema, fields
from marshmallow.decorators import post_load
class Vehicle:
def __init__(self, weight):
self.weight = weight
class VehicleSchema(Schema):
weight = fields.Float()
@post_load
def make_vehicle(self, data, **kwargs) -> Vehicle:
return Vehicle(**data)
class Bicycle(Vehicle):
def __init__(self, weight, amount_of_tires):
Vehicle.__init__(self, weight=weight)
self.amount_of_tires = amount_of_tires
class BicycleSchema(VehicleSchema):
amount_of_tires = fields.Integer()
@post_load
def make_bicycle(self, data, **kwargs) -> Bicycle:
return Bicycle(**data)
my_bicycle = Bicycle(weight=10, amount_of_tires=2)
schema = BicycleSchema()
json_string = schema.dumps(my_bicycle)
deserialised_my_bicycle = schema.loads(json_string)
print(deserialised_my_bicycle)
make_vehicle
和 make_bicycle
都注册为 post_load
钩子,因此它们被一个接一个地调用。当 make_vehicle
被调用时,make_bicycle
已经被调用,所以 type(data) == Bicycle
,因此你看到的错误。
我推荐以下解决方案:
class VehicleSchema(Schema):
model_class = Vehicle
weight = fields.Float()
@post_load
def make_vehicle(self, data, **kwargs) -> Vehicle:
return type(self).model_class(**data)
class BicycleSchema(VehicleSchema):
model_class = Bicycle
amount_of_tires = fields.Integer()
要使用此解决方案获得更准确的类型提示 - 可以在基础 VehicleSchema
class 上使用 Generic
和 TypeVar
(请参阅 https://docs.python.org/3/library/typing.html#typing.Generic) .