Type of object whose length

How do I enter a hint parameter or isinstancecheck an object that should be iterable and works with len? I assume that almost all objects with length are iterable, so it's really about what type, if any, represents objects that implement __len__.

def n_and_list(x: ???):
    return len(x), [y for y in x]

This is not typing.Iterableor collections.Iterable, because they are true for things that do not have length, for example zip.

In [1]: from typing import Iterable

In [2]: isinstance(zip([]), Iterable)
Out[3]: True

In [3]: from collections import Iterable

In [4]: isinstance(zip([]), Iterable)
Out[4]: True

In [5]: len(zip([]))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-27-86d411a5426c> in <module>()
----> 1 len(zip([]))

TypeError: object of type 'zip' has no len()

This is not typing.Sequenceor collections.Sequence, because they are false for things having a length, such as dictionary keys and numpy arrays.

In [6]: from typing import Sequence

In [7]: isinstance({}.keys(), Sequence)
Out[7]: False

In [8]: from numpy import asarray

In [9]: isinstance(asarray([]), Sequence)
Out[9]: False

In [10]: from collections import Sequence

In [11]: isinstance({}.keys(), Sequence)
Out[11]: False

In [12]: from numpy import asarray

In [13]: isinstance(asarray([]), Sequence)
Out[13]: False

This is not iterableor iterbecause they are not types. This is not listor tuplebecause they are too narrow.

+4
source share
3

collections.Sized :

def n_and_list(x: collections.Sized):
    return len(x), [y for y in x]

, , __len__ :

import typing
import collections

def n_and_list(x: typing.Union[collections.Sized, collections.Iterable]):
    return len(x), [y for y in x]

, , typing.Intersection, .

+2

typing.Collection, __contains__ :

class Collection(Sized, Iterable, Container):

    __slots__ = ()

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Collection:
            return _check_methods(C,  "__len__", "__iter__", "__contains__")
        return NotImplemented

, SizedIterable , , __contains__

class SizedIterable(Sized, Iterable):

    __slots__ = ()

    @classmethod
    def __subclasshook__(cls, C):
        if cls is SizedIterable:
            return _check_methods(C,  "__len__", "__iter__")
        return NotImplemented
+1
try:
    len(x)
    [y for y in x]
    # good type
except TypeError:
    # bad type

Take care of your problem. If he does not leave comments to this extent.

0
source

Source: https://habr.com/ru/post/1695879/


All Articles