简体   繁体   English

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

[英]PyCharm type hinting custom list iteration

So I created a custom type that subclasses from list , which works well in most cases;所以我创建了一个自定义类型,它是list的子类,在大多数情况下效果很好; though I noticed that Pycharm has trouble figuring out type hint when iterating over an object of the custom class.虽然我注意到 Pycharm 在迭代自定义 class 的 object 时无法找出类型提示。

Here's how I define it:我是这样定义它的:

class MyList(list):

    def as_tuple(self):
        return tuple(self)

Then to test with, I just create a simple class A and then create a bunch of A objects:然后进行测试,我只创建一个简单的 class A然后创建一堆A对象:

from dataclasses import dataclass

@dataclass
class A:
    f1: str
    f2: int


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

I think the type hint might be unnecessary, as it looks like PyCharm correctly identifies it as MyList[A] in any case.我认为类型提示可能是不必要的,因为它看起来像 PyCharm 在任何情况下都正确地将其识别为 MyList MyList[A]

Accessing an element appears to work fine for type hinting purposes:访问一个元素似乎可以很好地用于类型提示: 在此处输入图像描述

But PyCharm can't seem to offer type hints when iterating over the list type:但是 PyCharm 在迭代list类型时似乎无法提供类型提示:

在此处输入图像描述

What I ended up doing so far is using typing.Generic in the class definition.到目前为止,我最终做的是在 class 定义中使用typing.Generic I found out I also need to implement my own __iter__ method in the class, simply so I can type annotate the return type;我发现我还需要在 class 中实现自己的__iter__方法,这样我就可以对返回类型进行类型注释; otherwise, it doesn't seem to work without it.否则,没有它似乎无法工作。

Here's my new changes so far:到目前为止,这是我的新变化:

from typing import Generic, TypeVar, Iterator


T = TypeVar('T')


class MyList(list, Generic[T]):

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

    ...

Which apparently seems to do the trick:这显然似乎可以解决问题: 在此处输入图像描述

So the question is, is there an easier way to get type hint for iteration in PyCharm over a list subclass without needing to set it up the way I have above?所以问题是,有没有一种更简单的方法可以在 PyCharm 中通过list子类获取迭代类型提示,而无需按照我上面的方式进行设置?

The other main concern I have is a slight hit to performance.我担心的另一个主要问题是对性能的轻微影响。 For example, I've timed the iterating using the following code as an example, and found that the second approach I've used is slower;例如,我以下面的代码为例对迭代进行计时,发现我使用的第二种方法较慢; this is not surprising though, since I've implemented a custom __iter__ , which introduces an additional method call.不过这并不奇怪,因为我已经实现了一个自定义__iter__ ,它引入了一个额外的方法调用。

from timeit import timeit

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

I'm tempted to use something complicated like a metaclass solution or else maybe just re-assigning the MyList.__iter__ method outside the class definition, but curious to see if anyone has any alternatives to the approach that I've used above.我很想使用像元类解决方案这样复杂的东西,或者可能只是在 class 定义之外重新分配MyList.__iter__方法,但很想知道是否有人可以替代我上面使用的方法。

You were on the right path but it's a little confusing how python type hinting works.您走在正确的道路上,但是 python 类型提示的工作原理有点令人困惑。

All you need to do is this and you dont need to override __iter__ .你需要做的就是这个,你不需要覆盖__iter__

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

Why this works is cause you are telling PyCharm that you are creating a class that inherits the abilities of a generic list.为什么这样做是因为您告诉 PyCharm 您正在创建一个继承通用列表功能的 class。

On the other hand inheriting list and Generic you tell PyCharm you want to inherit the abilities of list but not the abilities of a generic list .另一方面,继承listGeneric你告诉 PyCharm 你想继承list的能力而不是泛型list的能力。 Instead its a class that supports generics and has list abilities.相反,它的 class 支持 generics 并具有list功能。

As for performance, this will still hurt performance and that's ok.至于性能,这仍然会损害性能,没关系。 Python is not known for being performant and if your code really needs to be fast then you should either look into writing it in Cython or C and importing it into your script or migrating completely away from Python. Python 并不以高性能着称,如果您的代码确实需要快速,那么您应该考虑用 Cython 或 C 编写它并将其导入您的脚本或完全从 ZA7F5F32.3156B923721713FC 迁移

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM