PyCharm 类型提示自定义列表迭代

PyCharm type hinting custom list iteration

所以我创建了一个自定义类型,它是 list 的子class,在大多数情况下效果很好;尽管我注意到 Pycharm 在迭代自定义 class.

的对象时无法确定类型提示

我是这样定义的:

class MyList(list):

    def as_tuple(self):
        return tuple(self)

然后为了测试,我只创建了一个简单的 class A 然后创建了一堆 A 对象:

from dataclasses import dataclass

@dataclass
class A:
    f1: str
    f2: int


objects: MyList[A] = MyList([
    A('hello', 111),
    A('world', 222)
])

我认为类型提示可能是不必要的,因为看起来 PyCharm 在任何情况下都正确地将其识别为 MyList[A]

出于类型提示的目的,访问元素似乎工作正常:

但是 PyCharm 在遍历 list 类型时似乎无法提供类型提示:

到目前为止我最终做的事情 是在class 定义中使用typing.Generic。我发现我还需要在 class 中实现我自己的 __iter__ 方法,这样我就可以键入注释 return 类型;否则,没有它似乎无法工作。

这是我到目前为止的新变化:

from typing import Generic, TypeVar, Iterator


T = TypeVar('T')


class MyList(list, Generic[T]):

    def __iter__(self) -> Iterator[T]:
        return super().__iter__()

    ...

这显然可以解决问题:

所以问题是,是否有一种更简单的方法可以在 PyCharm 中通过 list subclass 获取迭代类型提示,而无需按照我的方式进行设置以上?

我主要担心的另一个问题是对性能的轻微影响。例如,我使用以下代码作为示例对迭代进行计时,发现我使用的第二种方法速度较慢;不过这并不奇怪,因为我已经实现了一个自定义 __iter__,它引入了一个额外的方法调用。

from timeit import timeit

print(timeit("for o in objects: ...", globals=globals()))

我很想使用像 metaclass 解决方案这样复杂的东西,或者可能只是在 class 定义之外重新分配 MyList.__iter__ 方法,但我想看看是否任何人都可以替代我上面使用的方法。

您走在正确的道路上,但有点令人困惑 python 类型提示的工作原理。

您需要做的就是这个,您不需要覆盖 __iter__

class MyList(list[T]):
    ...

之所以可行,是因为您告诉 PyCharm 您正在创建一个 class 来继承通用列表的功能。

另一方面,继承 listGeneric 你告诉 PyCharm 你想继承 list 的能力,而不是通用 [=12] 的能力=].相反,它是 class 支持泛型并具有 list 能力。

至于性能,这仍然会影响性能,这没关系。 Python 并不以高性能而著称,如果您的代码确实需要快速,那么您应该考虑用 Cython 或 C 编写它并将其导入您的脚本或完全远离 Python。