pycharm 如何正确指定接受字典值的参数类型?

ax6ht2ek  于 2022-12-29  发布在  PyCharm
关注(0)|答案(2)|浏览(154)

下面是几个函数:

from typing import Sequence

def avg(vals: Sequence[float]):
    return sum(val for val in vals) / len(vals)

def foo():
    the_dict = {'a': 1., 'b': 2.}
    return avg(the_dict.values())

PyCharm 2022.3在最后一行警告了the_dict.values()
应为类型"Sequence [float]",但得到了_dict_values [float,str]
但是这些值可以被迭代,并取其长度。
我试过了

from typing import Sequence, Union

def avg(vals: Union[Sequence[float], _dict_values]):
    ...

这听起来很疯狂,但也没起作用
建议?
我可以关闭该参数的类型,但我很好奇什么是正确的注解。

u3r8eeie

u3r8eeie1#

_dict_values不是Sequence(它更接近于Iterator),幸运的avg并不需要Sequence确保的所有东西,你只需要Iterable[float]来实现sumSized来实现len()

from collections.abc import Iterable, Sized
from typing import Protocol

class SupportsFloatMean(Iterable[float], Sized, Protocol):
    ...

def avg(vals: SupportsFloatMean):
    return sum(val for val in vals) / len(vals)
gmol1639

gmol16392#

如果你想让avg函数兼容最广泛的类型,你只需要一个支持Iterable协议(用在for-loop中)和Sized协议(用在len函数中)的类型,不幸的是,这两个协议都不能从另一个继承,正如你在这里看到的。
因此,您需要创建这两者的交集,这可以通过PEP544中提到的typing.Protocol实现(在本例中),@PeterSutton的回答中也使用了这一点。
如果你不想太冗长,不需要自定义协议,并且 * 几乎 * 一样广泛,你可以简单地使用Collection ABC。它继承自IterableSized以及Container。后者定义了__contains__方法,这意味着你可以用它来做in检查。从技术上讲,在avg函数中并不需要它。
很明显,Collection仍然是ValuesView的超类,正如您在这里看到的,因此您可以毫无困难地使用dict.values调用avg

from collections.abc import Collection

def avg(vals: Collection[float]) -> float:
    return sum(val for val in vals) / len(vals)

def foo() -> float:
    the_dict = {'a': 1., 'b': 2.}
    return avg(the_dict.values())

另外,不要忘记返回类型注解。-)

相关问题