如何在 Python 元类中键入 __new__ 方法,以便 mypy 满意

How to type the __new__ method in a Python metaclass so that mypy is happy

我正在尝试在 Python 的元类中键入 __new__ 方法,以便让 mypy 满意。代码将是这样的(取自 pep-3115 - “Python 3000 中的元类”并稍微精简):

from __future__ import annotations

from typing import Type


# The metaclass
class MetaClass(type):

    # The metaclass invocation
    def __new__(cls: Type[type], name: str, bases: tuple, classdict: dict) -> type:
        result = type.__new__(cls, name, bases, classdict)
        print('in __new__')
        return result


class MyClass(metaclass=MetaClass):
    pass

有了这个,mypy 抱怨,Incompatible return type for "__new__" (returns "type", but must return a subtype of "MetaClass"),指向行 def __new__

我也尝试过:

def __new__(cls: Type[MetaClass], name: str, bases: tuple, classdict: dict) -> MetaClass:

然后 mypy 抱怨(关于 return result 行):Incompatible return value type (got "type", expected "MetaClass").

我也尝试过使用类型 var (TSubMetaclass = TypeVar('TSubMetaclass', bound='MetaClass')),结果与使用 MetaClass.

相同

使用 super().__new__ 而不是 type.__new__ 给出了相似的结果。

正确的做法是什么?

首先,return类型是MetaClass,不是type。其次,您需要显式转换 return 值,因为 type.__new__ 不知道它是 returning MetaClass 的一个实例。 (它的特定 return 类型由它的第一个参数决定,静态未知。)

from __future__ import annotations

from typing import Type<b>, cast</b>


# The metaclass
class MetaClass(type):

    # The metaclass invocation
    def __new__(cls: Type[type], name: str, bases: tuple, classdict: dict) -> <b>MetaClass</b>:
        result = type.__new__(cls, name, bases, classdict)
        print('in __new__')
        return <b>cast(MetaClass, result)</b>


class MyClass(metaclass=MetaClass):
    pass

要使用super,需要调整cls参数的静态类型。

class MetaClass(type):

    # The metaclass invocation
    def __new__(cls: Type[<b>MetaClass</b>], name: str, bases: tuple, classdict: dict) -> MetaClass:
        result = <b>super().__new__(name, bases, classdict)</b>
        print('in __new__')
        return cast(MetaClass, result)