gpt4 book ai didi

python - 为什么我们可以继承 `typing.NamedTuple` ?

转载 作者:行者123 更新时间:2023-12-05 01:03:44 26 4
gpt4 key购买 nike

在 Python 3.6 之后,我们有 typing.NamedTuple ,它是 collections.namedtuple() 的类型化版本,我们可以像类一样继承它:

class Employee(NamedTuple):
name: str
id: int

collections.namedtuple相比,这个语法更漂亮,但是我还是看不懂它的实现,不管是看typing.py文件,还是做一些简单的测试,我们会发现它是一个函数而不是一个类:

# Python 3.10.6 typing.py
def NamedTuple(typename, fields=None, /, **kwargs):
"""..."""
if fields is None:
fields = kwargs.items()
elif kwargs:
raise TypeError("Either list of fields or keywords"
" can be provided to NamedTuple, not both")
try:
module = sys._getframe(1).f_globals.get('__name__', '__main__')
except (AttributeError, ValueError):
module = None
return _make_nmtuple(typename, fields, module=module)
>>> type(NamedTuple)
<class 'function'>

我知道它使用了一些元类魔法,但我不明白使用 class MyClass(NamedTuple) 时会发生什么。为此,我尝试自定义一个函数来继承:

>>> def func_for_inherit(*args, **kwargs):
... print(args, kwargs)
...
>>> class Foo(func_for_inherit):
... foo: str
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: function() argument 'code' must be code, not str

嗯,这得到了我无法理解的结果。继承用户定义的函数时,似乎调用了它的类。这背后发生了什么?

最佳答案

typing.NamedTuple 使用了一个非常深奥的功能,__mro_entries__ :

If a base that appears in class definition is not an instance of type, then an __mro_entries__ method is searched on it. If found, it is called with the original bases tuple. This method must return a tuple of classes that will be used instead of this base. The tuple may be empty, in such case the original base is ignored.

NamedTuple 函数定义后立即出现如下代码:

_NamedTuple = type.__new__(NamedTupleMeta, 'NamedTuple', (), {})

def _namedtuple_mro_entries(bases):
if len(bases) > 1:
raise TypeError("Multiple inheritance with NamedTuple is not supported")
assert bases[0] is NamedTuple
return (_NamedTuple,)

NamedTuple.__mro_entries__ = _namedtuple_mro_entries

这会将 NamedTuple.__mro_entries__ 设置为一个函数,告诉类创建系统使用实际类 _NamedTuple 作为基类。 (_NamedTuple然后利用元类特性进一步自定义类的创建过程,最终得到一个直接继承自tuple的类。)

关于python - 为什么我们可以继承 `typing.NamedTuple` ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73593736/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com