list
之上编写一个非常薄的包装器,我想定义一个名为
reduce
的方法,但我很难正确注释它,以便
pylance
、
mypy
和
pylint
剪切每当我使用该方法,甚至定义它时,他们都会抱怨。我很不安地意识到几乎所有 Python 内置库都没有类型注释。
无论如何,这是我的实现,
def reduce(self, func: Callable[[list[T], list[T]], list[T]] = lambda x, y: x + y, default: Optional[T] = None) -> 'List[T]': # type: ignore
from functools import reduce
if default is None: return List(reduce(func, self.list)) # type: ignore
return List(reduce(func, self.list, default)) # type: ignore
当我的 List
实际上是字符串列表时,这会失败
a: List[str] = List(['a', 'b'])
b = a.reduce(lambda x, y: x + y)
显然在这里,类型检查器和 linter 说他们期望 list[T]
,而我通过了
str
。
泛型类型,否则它无法完全推理你的类型。下面是一个使用支持reduce的通用类型的列表示例(因为我们强制它有一个 __add__
方法):
from functools import reduce
from typing import Sequence, TypeVar, Callable, Generic, Dict, Protocol, cast
A = TypeVar("A")
# define that our type supports the add operator, since it needs to be able to to reduce it
class SupportsAdd(Protocol[A]):
def __add__(self, __other: A) -> A:
...
T = TypeVar("T", bound=SupportsAdd)
def _reduce_default(x: T, y: T) -> T:
return x + y
# instead of using None as the default, we use a special object
# so that we can distinguish between None and a missing default
#
# (the underlying reduce function does the same thing)
_missing_default = object()
class MyList(Generic[T]):
def __init__(self, initialdata: Sequence[T]) -> None:
self.data = list(initialdata)
def __getitem__(self, i: int) -> T:
return self.data[i]
def __setitem__(self, i: int, v: T) -> None:
self.data[i] = v
def __len__(self) -> int:
return len(self.data)
def __delitem__(self, i: int) -> None:
del self.data[i]
def reduce(
self,
func: Callable[[T, T], T] = _reduce_default,
default: T = cast(T, _missing_default),
) -> T:
if default is _missing_default:
return reduce(_reduce_default, self.data)
else:
return reduce(func, self.data, default)
# just another method that uses the types
def add_keys(self, keys: Dict[T, int]) -> None:
for k in keys:
self.data.append(k)
它的一些用法:
def test() -> None:
ll: MyList[int] = MyList([1, 2, 3])
print(ll[1])
ll[1] = 5
print(ll[1])
# add some keys
ll.add_keys({30: 1, 50: 2, 60: 3})
print(len(ll))
val: int # define the type separately, mypy warns us if it doesnt match
val = ll.reduce()
print(val)
# using strings instead
ll2: MyList[str] = MyList(["a", "b", "c"])
print(ll2.reduce())
2
5
6
149
abc
如果您尝试使用某些不支持__add__
的类,
mypy
会警告您:
# test class to see if classes without __add__ fail
class NoAdd:
def __init__(self, v: int) -> None:
self.v = v
x: MyList[NoAdd] = [NoAdd(1)]
test.py:100: error: Type argument "NoAdd" of "MyList" must be a subtype of "SupportsAdd[Any]" [type-var]
test.py:100: error: Value of type variable "T" of "MyList" cannot be "NoAdd" [type-var]
Found 2 errors in 1 file (checked 1 source file)