【问题标题】:Marshmallow Schema and Class InheritanceMarshmallow Schema 和类继承
【发布时间】:2021-01-11 14:19:54
【问题描述】:

我是第一次使用 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)


【问题讨论】:

    标签: python marshmallow


    【解决方案1】:

    make_vehiclemake_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 类上使用 GenericTypeVar(请参阅 https://docs.python.org/3/library/typing.html#typing.Generic)。

    【讨论】:

    • 这是个好主意。您的示例中有一个小错误。我不得不将model_class 更改为instance_model。我建议将函数名称从 make_vehicle 更改为 deserialise 并删除类型提示,因为它现在最终可以是车辆或自行车。我说的对吗?
    • @unlimitedfox 发现我已经更新了。在此示例中,make_vehicle 和返回类型 Vehicle 是合适的,因为继承意味着 BicycleVehicle。正如我所指出的,类型提示可以通过使用泛型更具体 - 但我认为这会分散答案的注意力。
    • 我认为在return语句中我们必须将instance_model替换为model_class
    猜你喜欢
    • 1970-01-01
    • 2023-03-10
    • 2023-03-14
    • 2015-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多