You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为__getitem__定义支持泛型类型的Protocol的问题

定义兼容索引访问与长度获取的自定义Protocol

你的问题根源在于两点:一是list等容器的__getitem__是重载方法,你最初定义的协议签名模糊,类型检查器无法匹配;二是你的calculate_distances函数用到了len(),但协议未包含__len__方法。以下是针对性的解决方案:

核心方案:自定义轻量协议

我们可以定义一个只要求实现__len__和整数索引式__getitem__的协议,既兼容list、numpy.ndarray、polars.Series等常见容器,又避免了Sequence强制要求的count和index方法。

from typing import Protocol, TypeVar, Callable
import numpy as np

T = TypeVar('T')

class Indexable(Protocol[T]):
    """支持长度获取与整数索引访问的通用协议"""
    def __len__(self) -> int:
        ...
    def __getitem__(self, key: int) -> T:
        ...

def calculate_distances(
    things: Indexable[T],
    distance: Callable[[T, T], np.float64],
) -> np.ndarray[np.floating[Any], Any]:
    dists = np.empty((len(things), len(things)), dtype=np.float64)
    for i in range(len(things)):
        for j in range(len(things)):
            if i != j:
                dists[i, j] = distance(things[i], things[j])
    return dists

# 测试兼容场景
calculate_distances([1,2,3], lambda a,b: abs(a-b))  # 正常通过类型检查
calculate_distances(np.array([1.0,2.0,3.0]), lambda a,b: abs(a-b))  # 正常通过

为什么原始写法失效?

  1. 签名不匹配:list的__getitem__存在重载(支持int和slice参数),你最初的__getitem__(self, key)未指定参数类型,类型检查器无法确认该协议能接受整数索引,因此判定不兼容。
  2. 缺失必要方法:calculate_distances依赖len()获取容器长度,但原始协议未定义__len__,即使__getitem__匹配,类型检查也会失败。

超宽松兼容方案(忽略类型细节)

如果完全不关心__getitem__的参数和返回类型,仅需确保类型具备该方法,可使用以下写法:

from typing import Protocol, Any

class AnySeq(Protocol):
    def __getitem__(self, key: Any) -> Any:
        ...
    def __len__(self) -> int:
        ...

这种写法兼容所有实现了任意__getitem__和__len__的类型,代价是类型检查器无法提供things[i]的类型提示,但符合你“不介意返回类型检查”的需求。

内容的提问来源于stack exchange,提问作者iliya malecki

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 11:47:32