En Python, comment déterminer si un objet est itérable?

y a-t-il une méthode comme isiterable ? La seule solution que j'ai trouvée jusqu'à présent est d'appeler

hasattr(myObj, '__iter__')

mais je ne suis pas sûr à quel point cela est stupide.

832
demandé sur John Kugelman 2009-12-23 15:13:55

19 réponses

  1. vérifier pour __iter__ fonctionne sur les types de séquence, mais il manquerait par exemple sur les chaînes en Python 2 . Je voudrais savoir la bonne réponse aussi, d'ici là, voici une possibilité (qui fonctionnerait sur les cordes, aussi):

    try:
        some_object_iterator = iter(some_object)
    except TypeError as te:
        print some_object, 'is not iterable'
    

    le iter contrôle intégré pour la méthode __iter__ ou dans le cas de Chaînes la méthode __getitem__ .

  2. Une autre approche générale de pythonic est de supposer un itérable, puis d'échouer gracieusement si elle ne fonctionne pas sur l'objet donné. Le glossaire Python:

    le style de programmation pythonique qui détermine le type d'un objet par l'inspection de sa méthode ou de sa signature d'attribut plutôt que par une relation explicite avec un objet de type ("S'il ressemble à un canard et des charlatans comme un canard , il doit être un canard .") En mettant l'accent sur les interfaces plutôt que sur les types spécifiques, un code bien conçu améliore sa flexibilité en permettant la substitution polymorphe. Duck-typing évite de tests à l'aide de type() ou isinstance(). au lieu de cela, il emploie typiquement le style de programmation EAFP (plus facile de demander pardon que la Permission).

    ...

    try:
       _ = (e for e in my_object)
    except TypeError:
       print my_object, 'is not iterable'
    
  3. Le collections module fournit quelques classes de base abstraites, qui permettent de demander des classes ou des instances si elles fournissent une fonctionnalité particulière, par exemple:

    import collections
    
    if isinstance(e, collections.Iterable):
        # e is iterable
    

    cependant, cela ne vérifie pas les classes qui sont itérables par __getitem__ .

668
répondu miku 2018-05-13 11:13:23

Duck typing

try:
    iterator = iter(theElement)
except TypeError:
    # not iterable
else:
    # iterable

# for obj in iterator:
#     pass

contrôle de Type

utiliser les classes de base abstraites . Ils ont besoin d'au moins Python 2.6 et ne fonctionnent que pour les classes de nouveau style.

from collections.abc import Iterable   # import directly from collections for Python < 3.3

if isinstance(theElement, Iterable):
    # iterable
else:
    # not iterable

cependant, iter() est un peu plus fiable comme décrit par la documentation :

Vérification isinstance(obj, Iterable) détecte les classes qui sont enregistré comme Itérables ou qui ont une méthode __iter__() , mais il ne détecte pas les classes qui itèrent avec le __getitem__() méthode. Le seul moyen fiable de déterminer si un objet est itérable est d'appeler iter(obj) .

495
répondu Georg Schölly 2018-10-04 12:08:05

je voudrais apporter un peu plus de lumière sur l'interaction de iter , __iter__ et __getitem__ et ce qui se passe derrière les rideaux. Armé de cette connaissance, vous serez en mesure de comprendre pourquoi le mieux que vous pouvez faire est

try:
    iter(maybe_iterable)
    print('iteration will probably work')
except TypeError:
    print('not iterable')

je vais énumérer les faits d'abord et puis suivre avec un rappel rapide de ce qui se passe quand vous employez une boucle for en python, suivie d'une discussion pour illustrer les faits.

faits

  1. vous pouvez obtenir un itérateur de n'importe quel objet o en appelant iter(o) si au moins une des conditions suivantes est vraie:



    a) o a une méthode __iter__ qui renvoie un objet itérateur. Un itérateur est tout objet avec une méthode __iter__ et __next__ (Python 2: next ).



    b) o a une méthode __getitem__ .

  2. contrôle pour une instance de Iterable ou Sequence , ou contrôle pour la l'attribut __iter__ n'est pas suffisant.

  3. si un objet o ne met en œuvre que __getitem__ , mais pas __iter__ , iter(o) construira un itérateur qui tente de récupérer des éléments de o par indice entier, à partir de l'indice 0. L'itérateur attrapera n'importe quel IndexError (mais aucune autre erreur) qui est soulevé et puis soulève StopIteration lui-même.

  4. dans le sens le plus général, il n'y a aucun moyen de vérifier si l'itérateur retourné par iter est sain d'autre que de l'essayer.

  5. si un objet o met en œuvre __iter__ , la fonction iter assurer que l'objet retourné par __iter__ est un itérateur. Il n'y a pas de vérification générale si un objet ne met en œuvre que __getitem__ .

  6. __iter__ qui l'emporte. Si un objet o met en œuvre à la fois __iter__ et __getitem__ , iter(o) appellera __iter__ .

  7. si vous voulez rendre vos propres objets itérables, Toujours mettre en œuvre la méthode __iter__ .

"1519190920 des" boucles "de 15191420920"

afin de suivre, vous avez besoin d'une compréhension de ce qui se passe lorsque vous employez une boucle for en Python. Hésitez pas à aller directement à la section suivante si vous savez déjà.

lorsque vous utilisez for item in o pour un objet itérable o , Python appelle iter(o) et attend un objet itérateur comme valeur de retour. Un itérateur est tout objet qui met en œuvre une méthode __next__ (ou next en Python 2) et une méthode __iter__ .

par convention, la méthode __iter__ d'un itérateur doit retourner l'objet lui-même (c.-à-d. return self ). Python appelle alors next sur l'itérateur jusqu'à ce que StopIteration soit soulevé. Tout cela se produit implicitement, mais la démonstration suivante le rend visible:

import random

class DemoIterable(object):
    def __iter__(self):
        print('__iter__ called')
        return DemoIterator()

class DemoIterator(object):
    def __iter__(self):
        return self

    def __next__(self):
        print('__next__ called')
        r = random.randint(1, 10)
        if r == 5:
            print('raising StopIteration')
            raise StopIteration
        return r

itération sur un DemoIterable :

>>> di = DemoIterable()
>>> for x in di:
...     print(x)
...
__iter__ called
__next__ called
9
__next__ called
8
__next__ called
10
__next__ called
3
__next__ called
10
__next__ called
raising StopIteration

Discussion et illustrations

sur les points 1 et 2: Obtenir un itérateur et des contrôles peu fiables

considérer la classe suivante:

class BasicIterable(object):
    def __getitem__(self, item):
        if item == 3:
            raise IndexError
        return item

Appel iter avec une instance de BasicIterable retourne un itérateur sans aucun problème parce que BasicIterable met en œuvre __getitem__ .

>>> b = BasicIterable()
>>> iter(b)
<iterator object at 0x7f1ab216e320>

cependant, il est important de noter que b n'a pas l'attribut __iter__ et n'est pas considéré comme une instance de Iterable ou Sequence :

>>> from collections import Iterable, Sequence
>>> hasattr(b, '__iter__')
False
>>> isinstance(b, Iterable)
False
>>> isinstance(b, Sequence)
False

C'est pourquoi Fluent Python par Luciano Ramalho recommande d'appeler iter et de gérer le potentiel TypeError comme le moyen le plus précis de vérifier si un objet est itérable. Citant directement du livre:

depuis Python 3.4, la façon la plus précise de vérifier si un objet x est itérable est d'appeler iter(x) et de gérer une exception TypeError si ce n'est pas le cas. Ceci est plus exact que l'utilisation de isinstance(x, abc.Iterable) , parce que iter(x) considère également la méthode de l'héritage __getitem__ , tandis que Iterable ABC ne le fait pas.

au point 3: itération sur des objets qui ne fournissent que __getitem__ , mais pas __iter__

itérant sur une instance de BasicIterable fonctionne comme prévu: Python construit un itérateur qui essaie de récupérer des éléments par index, en commençant à zéro, jusqu'à ce qu'un IndexError soit soulevé. La méthode __getitem__ de l'objet Démo renvoie simplement le item qui a été fourni comme argument à __getitem__(self, item) par l'itérateur retourné par iter .

>>> b = BasicIterable()
>>> it = iter(b)
>>> next(it)
0
>>> next(it)
1
>>> next(it)
2
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

notez que l'itérateur soulève StopIteration quand il ne peut pas retourner l'article suivant et que le IndexError qui est soulevé pour item == 3 est manipulé à l'interne. C'est pourquoi la boucle au-dessus d'un BasicIterable avec une boucle for fonctionne comme prévu:

>>> for x in b:
...     print(x)
...
0
1
2

voici un autre exemple afin de ramener à la maison le concept de la façon dont l'itérateur retourné par iter tente d'accéder aux articles par index. WrappedDict n'hérite pas de dict , ce qui signifie que les instances n'auront pas __iter__ la méthode.

class WrappedDict(object): # note: no inheritance from dict!
    def __init__(self, dic):
        self._dict = dic

    def __getitem__(self, item):
        try:
            return self._dict[item] # delegate to dict.__getitem__
        except KeyError:
            raise IndexError

notez que les appels à __getitem__ sont délégués à dict.__getitem__ pour lequel la notation à crochets est simplement un raccourci.

>>> w = WrappedDict({-1: 'not printed',
...                   0: 'hi', 1: 'StackOverflow', 2: '!',
...                   4: 'not printed', 
...                   'x': 'not printed'})
>>> for x in w:
...     print(x)
... 
hi
StackOverflow
!

aux points 4 et 5: iter vérifie l'existence d'un itérateur lorsqu'il appelle __iter__ :

quand iter(o) est appelé pour un objet o , iter fera en sorte que le retour la valeur de __iter__ , si la méthode est présent, est un itérateur. Cela signifie que l'objet retourné doit implémenter __next__ (ou next en Python 2) et __iter__ . iter ne peut pas effectuer de contrôles de santé mentale pour les objets qui fournir __getitem__ , parce qu'il n'a aucun moyen de vérifier si les éléments de l'objet sont accessibles par un index entier.

class FailIterIterable(object):
    def __iter__(self):
        return object() # not an iterator

class FailGetitemIterable(object):
    def __getitem__(self, item):
        raise Exception

noter que la construction d'un itérateur à partir des instances FailIterIterable échoue immédiatement, en construisant un itérateur de FailGetItemIterable réussit, mais lancera une Exception sur le premier appel à __next__ .

>>> fii = FailIterIterable()
>>> iter(fii)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: iter() returned non-iterator of type 'object'
>>>
>>> fgi = FailGetitemIterable()
>>> it = iter(fgi)
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/path/iterdemo.py", line 42, in __getitem__
    raise Exception
Exception

Sur le point 6: __iter__ gagne

celui-ci est simple. Si un objet met en œuvre __iter__ et __getitem__ , iter appellera __iter__ . Considérons la classe suivante

class IterWinsDemo(object):
    def __iter__(self):
        return iter(['__iter__', 'wins'])

    def __getitem__(self, item):
        return ['__getitem__', 'wins'][item]

et le sortie en boucle sur une instance:

>>> iwd = IterWinsDemo()
>>> for x in iwd:
...     print(x)
...
__iter__
wins

Sur le point 7: votre objet iterable les classes à mettre en œuvre __iter__

vous pourriez vous demander pourquoi la plupart des séquences bâties comme list implémentent une méthode __iter__ alors que __getitem__ serait suffisant.

class WrappedList(object): # note: no inheritance from list!
    def __init__(self, lst):
        self._list = lst

    def __getitem__(self, item):
        return self._list[item]

après tout, itération sur les instances de la classe ci-dessus, que les délégués appelle à __getitem__ à list.__getitem__ (à l'aide de la notation crochets), fonctionnera très bien:

>>> wl = WrappedList(['A', 'B', 'C'])
>>> for x in wl:
...     print(x)
... 
A
B
C

les raisons pour lesquelles vos itérables personnalisés devraient implémenter __iter__ sont les suivantes:

  1. si vous implémentez __iter__ , les instances seront considérées comme itérables, et isinstance(o, collections.Iterable) retournera True .
  2. Si l'objet renvoyé par __iter__ n'est pas un itérateur, iter sera échouer immédiatement et élever une TypeError .
  3. la manipulation spéciale de __getitem__ existe pour des raisons de rétrocompatibilité. Citant à nouveau de Fluent Python:

C'est pourquoi toute séquence Python est itérable: ils implémentent tous __getitem__ . Effectivement, les séquences standard mettent aussi en œuvre __iter__ , et la vôtre devrait aussi, parce que le la manipulation spéciale de __getitem__ existe pour l'arrière des raisons de compatibilité et peut être disparu dans l'avenir (même si elle n'est pas déconseillée pendant que j'écris ceci).

62
répondu timgeb 2016-04-04 16:04:01

ce n'est pas suffisant: l'objet retourné par __iter__ doit implémenter le protocole d'itération (c'est-à-dire la méthode next ). Voir la section pertinente de la" documentation 151930920 .

en Python, une bonne pratique est d '" essayer de voir "au lieu de"vérifier".

28
répondu jldupont 2017-01-27 17:01:02
try:
  #treat object as iterable
except TypeError, e:
  #object is not actually iterable

Ne pas exécuter des vérifications pour voir si votre canard est vraiment un canard pour voir si il est itératif ou pas, la traiter comme si elle était et de se plaindre, si ce n'était pas le cas.

18
répondu badp 2009-12-23 12:28:00

la meilleure solution que j'ai trouvée jusqu'à présent:

hasattr(obj, '__contains__')

qui vérifie essentiellement si l'objet implémente l'opérateur in .

avantages (aucune des autres solutions n'a les trois):

  • c'est une expression (fonctionne comme un lambda , par opposition à la essayer...sauf variante)
  • il est (devrait être) mis en œuvre par tous les iterables, y compris chaînes (par opposition à __iter__ )
  • fonctionne sur N'importe quel Python > = 2.5

Notes:

  • la philosophie Python de "demander pardon, pas de permission" ne fonctionne pas bien lorsque, par exemple, dans une liste, vous avez à la fois des itérables et des non-itérables et que vous devez traiter chaque élément différemment selon son type (en traitant les itérables sur try et non-itérables sur sauf serait travail, mais il paraîtrait butt-laid et trompeuse)
  • les solutions à ce problème qui tentent de réellement itérer au-dessus de l'objet (par exemple [x pour x dans obj]) pour vérifier s'il est itérable peut induire des pénalités de performance significatives pour les grandes itérables (surtout si vous avez juste besoin des premiers éléments de l'itérable, par exemple) et doit être évitée
16
répondu Vlad 2017-09-18 15:47:00

en Python <= 2.5, vous ne pouvez pas et ne devriez pas - iterable était une interface" informelle".

mais depuis Python 2.6 et 3.0, vous pouvez tirer parti de la nouvelle infrastructure ABC (abstract base class) avec quelques ABC intégrés qui sont disponibles dans le module collections:

from collections import Iterable

class MyObject(object):
    pass

mo = MyObject()
print isinstance(mo, Iterable)
Iterable.register(MyObject)
print isinstance(mo, Iterable)

print isinstance("abc", Iterable)

Maintenant, si cela est souhaitable ou fonctionne réellement, c'est juste une question de conventions. Comme vous pouvez le voir, vous can enregistrer un non-itérable objet Itérable - et il déclenche une exception à l'exécution. Par conséquent, isinstance acquiert un" nouveau "sens - il vérifie simplement la compatibilité de type" déclaré", ce qui est une bonne façon d'aller en Python.

par contre, si votre objet ne satisfait pas l'interface dont vous avez besoin, que ferez-vous? Prenons l'exemple suivant:

from collections import Iterable
from traceback import print_exc

def check_and_raise(x):
    if not isinstance(x, Iterable):
        raise TypeError, "%s is not iterable" % x
    else:
        for i in x:
            print i

def just_iter(x):
    for i in x:
        print i


class NotIterable(object):
    pass

if __name__ == "__main__":
    try:
        check_and_raise(5)
    except:
        print_exc()
        print

    try:
        just_iter(5)
    except:
        print_exc()
        print

    try:
        Iterable.register(NotIterable)
        ni = NotIterable()
        check_and_raise(ni)
    except:
        print_exc()
        print

si l'objet ne satisfait pas ce que vous attendez, vous lancez juste une erreur de typographie, mais si L'ABC approprié a été enregistrée, votre chèque est inutile. Au contraire, si la méthode __iter__ est disponible, Python reconnaîtra automatiquement l'objet de cette classe comme étant itérable.

donc, si vous attendez juste un itérable, itérez-le et oubliez-le. D'un autre côté, si vous avez besoin de faire des choses différentes selon le type d'entrée, vous pourriez trouver L'infrastructure ABC assez utile.

15
répondu Alan Franzoni 2016-08-10 21:55:26

j'ai trouvé une bonne solution ici :

isiterable = lambda obj: isinstance(obj, basestring) \
    or getattr(obj, '__iter__', False)
11
répondu jbochi 2016-08-10 21:52:55

vous pourriez essayer ceci:

def iterable(a):
    try:
        (x for x in a)
        return True
    except TypeError:
        return False

si nous pouvons faire un générateur qui itère au-dessus (mais ne jamais utiliser le générateur de sorte qu'il ne prend pas de place), il est itérable. On dirait un truc du genre" duh". Pourquoi devez-vous déterminer si une variable est itérable en premier lieu?

10
répondu Chris Lutz 2009-12-23 12:21:12

selon le Python 2 Glossary , les itérables sont

tous les types de séquence (tels que list , str , et tuple ) et certains types de non-séquence comme dict et file et les objets de n'importe quelle classe que vous définissez avec une méthode __iter__() ou __getitem__() . Iterables peut être utilisé dans une boucle for et dans beaucoup d'autres endroits où une séquence est nécessaire (zip(), map(), ...). Lorsqu'un objet itérable est passé comme argument à la fonction intégrée d'iter(), elle renvoie un itérateur sur l'objet.

bien sûr, étant donné le style de codage général pour Python basé sur le fait qu'il est "plus facile de demander le pardon que la permission.", l'attente générale est d'utiliser des

try:
    for i in object_in_question:
        do_something
except TypeError:
    do_something_for_non_iterable

mais si vous avez besoin de le vérifier explicitement, vous pouvez tester pour un itérable par hasattr(object_in_question, "__iter__") or hasattr(object_in_question, "__getitem__") . Vous devez vérifier pour les deux, parce que str s n'ont pas une méthode __iter__ (du moins pas en Python 2, mais en Python 3) et parce que les objets generator n'ont pas de méthode __getitem__ .

8
répondu Anaphory 2014-11-25 10:14:50

je trouve souvent commode, à l'intérieur de mes scripts, de définir une fonction iterable . (Incorpore maintenant la simplification suggérée par Alfe):

import collections

def iterable(obj):
    return isinstance(obj, collections.Iterable):

ainsi vous pouvez tester si n'importe quel objet est itérable dans la forme très lisible

if iterable(obj):
    # act on iterable
else:
    # not iterable

comme vous le feriez avec la fonction callable 151970920"

modifier: si vous avez numpy installé, vous pouvez simplement faire: à partir de numpy import iterable , qui est tout simplement quelque chose comme

def iterable(obj):
    try: iter(obj)
    except: return False
    return True

si vous n'avez pas de numpy, vous pouvez simplement implémenter ce code, ou celui ci-dessus.

4
répondu fmonegaglia 2014-01-26 15:52:54

a une fonction intégrée comme celle-ci:

from pandas.util.testing import isiterable
4
répondu Sören 2017-05-12 12:27:19

depuis Python 3.5 vous pouvez utiliser le module Dactylographie de la bibliothèque standard pour les choses liées au type:

from typing import Iterable

...

if isinstance(my_item, Iterable):
    print(True)
4
répondu Rotareti 2018-05-04 13:13:26
def is_iterable(x):
    try:
        0 in x
    except TypeError:
        return False
    else:
        return True

cela dira oui à toutes sortes d'objets itérables, mais il dira non aux chaînes en Python 2 . (C'est ce que je veux par exemple quand une fonction récursive pourrait prendre une chaîne ou un conteneur de chaînes. Dans cette situation, demander pardon peut conduire à obfuscode, et il est préférable de demander la permission d'abord.)

import numpy

class Yes:
    def __iter__(self):
        yield 1;
        yield 2;
        yield 3;

class No:
    pass

class Nope:
    def __iter__(self):
        return 'nonsense'

assert is_iterable(Yes())
assert is_iterable(range(3))
assert is_iterable((1,2,3))   # tuple
assert is_iterable([1,2,3])   # list
assert is_iterable({1,2,3})   # set
assert is_iterable({1:'one', 2:'two', 3:'three'})   # dictionary
assert is_iterable(numpy.array([1,2,3]))
assert is_iterable(bytearray("not really a string", 'utf-8'))

assert not is_iterable(No())
assert not is_iterable(Nope())
assert not is_iterable("string")
assert not is_iterable(42)
assert not is_iterable(True)
assert not is_iterable(None)

beaucoup d'autres stratégies ici diront oui aux cordes. Utiliser si qu'est ce que vous voulez.

import collections
import numpy

assert isinstance("string", collections.Iterable)
assert isinstance("string", collections.Sequence)
assert numpy.iterable("string")
assert iter("string")
assert hasattr("string", '__getitem__')

Note: is_iterable() dira oui aux chaînes de type bytes et bytearray .

  • bytes les objets en Python 3 sont itérables True == is_iterable(b"string") == is_iterable("string".encode('utf-8')) il n'y a pas un tel type en Python 2.
  • bytearray les objets en Python 2 et 3 sont itérables True == is_iterable(bytearray(b"abc"))

L'O. P. hasattr(x, '__iter__') approche va dire oui pour les chaînes de caractères en Python 3 et non en Python 2 (Peu importe si '' ou b'' ou u'' ). Merci à @LuisMasuelli d'avoir remarqué que vous tomberez aussi sur un buggy __iter__ .

2
répondu Bob Stein 2017-09-25 20:02:17

la manière la plus simple, en respectant le Duck typing du Python, est d'attraper l'erreur (Python sait parfaitement ce qu'il attend d'un objet pour devenir un itérateur):

class A(object):
    def __getitem__(self, item):
        return something

class B(object):
    def __iter__(self):
        # Return a compliant iterator. Just an example
        return iter([])

class C(object):
    def __iter__(self):
        # Return crap
        return 1

class D(object): pass

def iterable(obj):
    try:
        iter(obj)
        return True
    except:
        return False

assert iterable(A())
assert iterable(B())
assert iterable(C())
assert not iterable(D())

Notes :

  1. la distinction entre un objet non itérable ou un buggy __iter__ a été implémentée, si le type d'exception est le même: de toute façon, vous ne serez pas en mesure pour effectuer une itération de l'objet.
  2. je pense que je comprends votre préoccupation: comment callable existe en tant que contrôle si je pouvais également compter sur duck dactylographier pour soulever un AttributeError si __call__ n'est pas défini pour mon objet, mais ce n'est pas le cas pour la vérification itérable?

    Je ne sais pas la réponse, mais vous pouvez soit mettre en œuvre la fonction que j'AI (et d'autres utilisateurs) donné, ou tout simplement attraper l'exception dans votre code (votre mise en œuvre dans cette partie sera comme la fonction que j'ai écrite - assurez-vous juste d'isoler la création iterator du reste du code de sorte que vous pouvez capturer l'exception et la distinguer d'un autre TypeError .

1
répondu Luis Masuelli 2016-08-10 21:57:15

le isiterable func au code suivant renvoie True si l'objet est itérable. si ce n'est pas itératif renvoie False

def isiterable(object_):
    return hasattr(type(object_), "__iter__")

exemple

fruits = ("apple", "banana", "peach")
isiterable(fruits) # returns True

num = 345
isiterable(num) # returns False

isiterable(str) # returns False because str type is type class and it's not iterable.

hello = "hello dude !"
isiterable(hello) # returns True because as you know string objects are iterable
1
répondu Nomad 2017-09-16 01:44:14

au lieu de vérifier l'attribut __iter__ , vous pouvez vérifier l'attribut __len__ , qui est implémenté par chaque composant de python itérable, y compris les chaînes.

>>> hasattr(1, "__len__")
False
>>> hasattr(1.3, "__len__")
False
>>> hasattr("a", "__len__")
True
>>> hasattr([1,2,3], "__len__")
True
>>> hasattr({1,2}, "__len__")
True
>>> hasattr({"a":1}, "__len__")
True
>>> hasattr(("a", 1), "__len__")
True

Aucun-les objets itérables ne mettraient pas en œuvre ceci pour des raisons évidentes. Cependant, on n'attrape pas définie par l'utilisateur iterables qui ne mettent pas en œuvre, ni générateur d'expressions, qui iter . Cependant, cela peut être fait en une ligne, et l'ajout d'un une simple vérification de l'expression or pour les générateurs réglerait ce problème. (Notez qu'écrire type(my_generator_expression) == generator lancerait un NameError . Référez-vous à ce réponse à la place.)

vous pouvez utiliser GeneratorType des types:

>>> import types
>>> types.GeneratorType
<class 'generator'>
>>> gen = (i for i in range(10))
>>> isinstance(gen, types.GeneratorType)
True

- - - réponse acceptée par utdemir

(ceci le rend utile pour vérifier si vous pouvez appeler len sur l'objet cependant.)

0
répondu DarthCadeus 2018-08-14 08:25:19

il m'a toujours échappé pourquoi python a callable(obj) -> bool mais pas iterable(obj) -> bool ...

c'est sûrement plus facile de faire hasattr(obj,'__call__') même si c'est plus lent.

comme presque toutes les autres réponses recommandent d'utiliser try / except TypeError , où les tests d'exceptions sont généralement considérés comme une mauvaise pratique dans n'importe quelle langue, voici une mise en œuvre de iterable(obj) -> bool j'ai pris plus d'affection et d'utilisation souvent:

pour pour python 2, j'utiliserai un lambda juste pour augmenter mes performances...

(en python 3, peu importe ce que vous utilisez pour définir la fonction, def a à peu près la même vitesse que lambda )

iterable = lambda obj: hasattr(obj,'__iter__') or hasattr(obj,'__getitem__')

notez que cette fonction s'exécute plus rapidement pour les objets avec __iter__ puisqu'elle ne teste pas pour __getitem__ .

la plupart des objets itérables doivent s'appuyer sur __iter__ lorsque des objets spéciaux revenir à __getitem__ , bien que ce soit est nécessaire pour qu'un objet soit itératif.

(et puisqu'il s'agit d'une norme, elle affecte également les objets C)

0
répondu Tcll 2018-08-14 16:18:03

mis à part l'essai régulier et sauf, vous pouvez exécuter l'aide.

temp= [1,2,3,4]
help(temp)

aide donnerait toutes les méthodes qui pourraient être exécutées sur cet objet(il pourrait être n'importe quel objet et peut ne pas être une liste comme par exemple), qui est temp dans ce cas.

Note: Ce serait quelque chose que vous feriez manuellement.

-2
répondu prudhvi Indana 2017-11-30 15:47:16