如何将递归 `.json()` 方法添加到 **NamedTuple** 的子类

How to add recursive `.json()` method to subclass of **NamedTuple**

我目前有几个 classes 遵循下面代码中描述的模式:

from typing import NamedTuple

class Data(NamedTuple):
   name: str,
   value: float
   
   def json(self):
       return {'name': self.name, 'value': self.value}
    

我不想在我创建的每个新 class 中定义一个 json 方法,我想扩展 typing.NamedTuple,这样我就可以从我的新 class 扩展] 而不必在 subclasses 中定义 json 方法。 typing.NamedTuple 已经提供了 _asdict 方法,但是这个方法是不够的,因为它不是递归的(Nested namedtuples 不会被转换为 dict 对象)。

我已经尝试在下面的代码中尝试这样做:

class JsonNamedTuple(NamedTuple):
    def json(self):
        # some slightly complex recursive code here

class Data(JsonNamedTuple):
    name: str,
    value: float

a = Data('asdf', 0.5)

我收到这个错误: TypeError: <lambda>() takes 1 positional argument but 3 were given

有没有办法扩展 typing.NamedTuple 而不会出现此错误?

遗憾的是,您实际上无法扩展 typing.NamedTuple

但是您可以像这样创建一个 class 装饰器:

import typing

class _JsonMixin:
    def json(self):
        # some slightly complex recursive code here
        return {'name': self.name, 'value': self.value}

def jsonable(cls):
    cls.__bases__ = (_JsonMixin,) + cls.__bases__
    return cls

@jsonable
class Data(typing.NamedTuple):
    name: str
    value: float

思维类型检查员不会理解 .json() 从何而来。 修改 __bases__ 优于创建新的 class 并继承 cls,并且与注入 .json().

不同,可以轻松支持更多方法

如果您不想使用 class 装饰器,您可以创建一个元 class,但这有点复杂。 metaclass 也不适用于类型检查器。