从 List[type] 继承时出现 Pylint 错误

Pylint error when inheriting from List[type]

我写了下面这段代码:

from typing import List

class Foo():
    def __init__(self, _a : int, _b : bool):
        self.a = _a
        self.b = _b

class Bar(List[Foo]):
    def print(self):
        for entry in self: # Non-iterable value self is used in an iterating contextpylint(not-an-iterable)
            print(entry.a)
            print(entry.b)

foo0 = Foo(0, True)
foo1 = Foo(1, False)
foo2 = Foo(2, True)
foo3 = Foo(3, False)
bar = Bar()
bar.append(foo0) # Instance of 'Bar' has no 'append' memberpylint(no-member)
bar.append(foo1) # Instance of 'Bar' has no 'append' memberpylint(no-member)
bar.append(foo2) # Instance of 'Bar' has no 'append' memberpylint(no-member)
bar.append(foo3) # Instance of 'Bar' has no 'append' memberpylint(no-member)

bar.print()

它运行得很好,似乎做了它应该做的事情,但 Pylint 似乎真的不喜欢它(评论中的错误消息)。

有办法让这个停止吗?

这将修复所有 Pylint 错误

from typing import List
class Foo():
    def __init__(self, _a : int, _b : bool):
        self.a = _a
        self.b = _b

class Bar(List[Foo]):
    def print(self):
        for entry in list(self):
            print(entry.a)
            print(entry.b)

foo0 = Foo(0, True)
foo1 = Foo(1, False)
foo2 = Foo(2, True)
foo3 = Foo(3, False)

bar = Bar([foo0,foo1,foo2,foo3])
bar.print()

正如其他人在评论中指出的那样,List[Foo] 不是 list 类型,而是 类型提示 某些类型检查器(例如 mypy) 将用于分析您的代码。类型提示的正确用法是这样的:

a: List[int] = [1, 2, 3]  # a is a list of ints
b: List[float] = []
b.append(1.0)
b.append("string")  # a type checker would point out that this is an error

另一方面,子类化内置 list 类型可能不会给您想要的结果。至少在 CPython 中,像 listdict 这样的内置类型出于性能原因在 C 中实现了大部分方法,因此无法直接覆盖某些行为。阅读 this article 了解更多详情。

然而,Python 确实提供了一个 UserList class that supports inheritance. It basically implements list behaviors in pure Python, so it has worse performance, but is more customizable. To only permit objects of certain types to be added to the list, you can just override the append method (and extend and __iadd__+=)如果你想要完整)并手动进行类型检查:

from collections import UserList

class Bar(UserList):
    def append(self, item):
        if not isinstance(item, Foo):
            raise ValueError
        super().append(item)

    def extend(self, items):
        if any(not isinstance(x, Foo) for x in items):
            raise ValueError
        super().extend(items)

    def __iadd__(self, items):
        self.extend(items)
        return self

    def print(self):
        for entry in self:
            print(entry.a)
            print(entry.b)

你可以验证一下,当下面的代码是运行时:

foo0 = Foo(0, True)
foo1 = Foo(1, False)
foo2 = Foo(2, True)
foo3 = Foo(3, False)
bar = Bar()
bar.append(foo0)
bar.extend([foo1])
bar += [foo2, foo3]

# Check that exceptions are correctly raised.
try:
    bar.append(None)
except ValueError:
    pass
else:
    print("Exception not raised")
try:
    bar += [foo0, foo1, None]
except ValueError:
    pass
else:
    print("Exception not raised")

bar.print()

我们会得到:

0
True
1
False
2
True
3
False