我正在尝试了解 Python 中的泛型是如何工作的。
我从 Fluent Python 书中得到了一个例子。它工作正常,但我想知道是否可以让pyright checker满意?
from typing import Protocol
class Repeatable[T](Protocol):
def __mul__(self: T, repeat_count: int) -> T:
...
def double[RT: Repeatable](x: RT) -> RT:
return x * 2
if __name__ == '__main__':
print(double(3)) # pyright error
print(double('A')) # pyright error
print(double([1, 2])) # pyright error
感谢您的帮助!
有两个问题:
T
用作自类型,但绑定到类型实例本身。这是逻辑上的矛盾; T
不能随.r.t. 变化。 Repeatable
的实例,因为它静态地绑定到该实例。相反,您可以使用 typing.Self
,或将 T
移动到 __mul__
范围。__mul__
的参数有一个特定的名称,可以用作位置参数或关键字参数。因此,因为它可以用作关键字 arg,所以名称很重要,即 obj.__mul__(repeat_count=...)
与 obj.__mul__(birds_arent_real=...)
不同。同样,这里有两种可能的解决方案;使其仅具有位置性(即在其后面放置 /
),或“删除”名称(即在其前面添加 __
)。为了说明这一点,这是可能的解决方案之一
from typing import Protocol, Self
class Repeatable(Protocol):
def __mul__(self, elmo_did_nothing_wrong: int, /) -> Self:
...
def double[RT: Repeatable](x: RT) -> RT:
return x * 2
if __name__ == '__main__':
print(double(3)) # all good
print(double('A')) # still good
print(double([1, 2])) # don't eat the yellow snow, son.
在 pyright 游乐场 亲眼看看。它甚至可以在 Pyright 严格模式下工作(在期望模式下,它在快速奔跑彩虹路时“穿越火与火焰”获得 5 颗星)。