Home > Software design >  How to properly specify argument type accepting dictionary values, so as to not warn in PyCharm (pyt
How to properly specify argument type accepting dictionary values, so as to not warn in PyCharm (pyt

Time:12-26

Here are a couple of functions:

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 warns about the_dict.values() in the last line:

Expected type 'Sequence[float]', got _dict_values[float, str] instead

But .. those values can be iterated across and have their length taken.

I tried

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

which seems insane, but also didn't work.

Suggestions?

I can turn off the typing for that arg, but I am curious what the right thing is.

CodePudding user response:

_dict_values is not a Sequence (it's closer to an Iterator). Lucky avg doesn't require everything Sequence ensures. You only need Iterable[float] for sum and Sized for len().

from typing import Iterable, Protocol, Sized


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


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

CodePudding user response:

Reference: https://docs.python.org/3/library/stdtypes.html?highlight=dict#dictionary-view-objects

The objects returned by dict.keys(), dict.values() and dict.items() are view objects. Dictionary views can be iterated over to yield their respective data, and support membership tests.

iter(dictview): Return an iterator over the keys, values or items (represented as tuples of (key, value)) in the dictionary.

from typing import Union, Iterable, Sized


def avg(vals: Union[Iterable[float], Sized]) -> float:
    return sum(val for val in vals) / len(vals)


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


if __name__ == '__main__':
    print(foo())
  • Related