Gibt es eine Methode wie isiterable
? Die einzige Lösung, die ich bisher gefunden habe, ist den folgenden Aufruf:
hasattr(myObj, '__iter__')
Aber ich bin mir nicht sicher, wie zuverlässig das ist.
Gibt es eine Methode wie isiterable
? Die einzige Lösung, die ich bisher gefunden habe, ist den folgenden Aufruf:
hasattr(myObj, '__iter__')
Aber ich bin mir nicht sicher, wie zuverlässig das ist.
Das Überprüfen von __iter__
funktioniert bei Sequenztypen, würde aber z. B. bei Zeichenketten in Python 2 fehlschlagen. Ich würde auch gerne die richtige Antwort wissen, bis dahin hier ist eine Möglichkeit (die auch bei Zeichenketten funktionieren würde):
try:
some_object_iterator = iter(some_object)
except TypeError as te:
print(some_object, 'ist nicht iterierbar')
Die eingebaute Funktion iter
überprüft die Methode __iter__
oder im Falle von Zeichenketten die Methode __getitem__
.
Pythonischer Programmierstil, der den Typ eines Objekts durch Inspektion seiner Methode oder Attributsignatur bestimmt statt durch eine explizite Beziehung zu einem bestimmten Typobjekt ("Wenn es wie eine Ente aussieht und wie eine Ente quakt, dann muss es eine Ente sein."). Durch Betonung von Schnittstellen anstelle von spezifischen Typen verbessert gut gestalteter Code seine Flexibilität, indem er polymorphe Substitution ermöglicht. Duck-Typing vermeidet Tests mit type() oder isinstance(). Stattdessen verwendet es typischerweise den EAFP (Easier to Ask Forgiveness than Permission) Programmierstil.
...
try: _ = (e for e in my_object) except TypeError: print my_object, 'ist nicht iterierbar'
Das collections
Modul bietet einige abstrakte Basisklassen, mit denen man Klassen oder Instanzen fragen kann, ob sie eine bestimmte Funktionalität bereitstellen, zum Beispiel:
from collections.abc import Iterable
if isinstance(e, Iterable):
# e ist iterierbar
Allerdings wird hierbei nicht überprüft, ob Klassen iterierbar sind durch __getitem__
.
try:
iterator = iter(the_element)
except TypeError:
# nicht iterierbar
else:
# iterierbar
# für obj in iterator:
# pass
Verwenden Sie die Abstract Base Classes. Sie benötigen mindestens Python 2.6 und funktionieren nur für neuartige Klassen.
from collections.abc import Iterable # direkt aus collections importieren für Python < 3.3
if isinstance(the_element, Iterable):
# iterierbar
else:
# nicht iterierbar
Allerdings ist iter()
wie in der Dokumentation beschrieben etwas zuverlässiger:
Bei der Überprüfung von
isinstance(obj, Iterable)
werden Klassen erkannt, die als Iterable registriert sind oder über eine__iter__()
-Methode verfügen, jedoch nicht Klassen, die mit der__getitem__()
-Methode iterieren. Der einzige zuverlässige Weg zu bestimmen, ob ein Objekt iterierbar ist, besteht darin,iter(obj)
aufzurufen.
Ich habe dieses Problem in letzter Zeit ziemlich intensiv studiert. Basierend darauf ist mein Fazit, dass dies heutzutage der beste Ansatz ist:
from collections.abc import Iterable # mit Python 2.7 oder niedriger '.abc' weglassen
def iterable(obj):
return isinstance(obj, Iterable)
Das oben Genannte wurde bereits früher empfohlen, aber der allgemeine Konsens war, dass es besser wäre, iter()
zu verwenden:
def iterable(obj):
try:
iter(obj)
except Exception:
return False
else:
return True
Wir haben in unserem Code auch iter()
zu diesem Zweck verwendet, aber in letzter Zeit habe ich mich mehr und mehr über Objekte geärgert, die nur __getitem__
haben und als iterierbar betrachtet werden. Es gibt gültige Gründe, __getitem__
in einem nicht-iterierbaren Objekt zu haben, und mit ihnen funktioniert der obige Code nicht gut. Als ein echtes Beispiel können wir Faker verwenden. Der obige Code meldet, dass es iterierbar ist, aber beim Versuch, es zu durchlaufen, tritt ein AttributeError
auf (getestet mit Faker 4.0.2):
>>> from faker import Faker
>>> fake = Faker()
>>> iter(fake) # Keine Ausnahme, muss iterierbar sein
>>> list(fake) # Ups
Traceback (most recent call last):
File "", line 1, in
File "/home/.../site-packages/faker/proxy.py", line 59, in __getitem__
return self._factory_map[locale.replace('-', '_')]
AttributeError: 'int' object has no attribute 'replace'
Wenn wir isinstance()
verwenden würden, würden wir versehentlich Faker-Instanzen (oder andere Objekte, die nur __getitem__
haben) nicht als iterierbar betrachten:
>>> from collections.abc import Iterable
>>> from faker import Faker
>>> isinstance(Faker(), Iterable)
False
Frühere Antworten haben kommentiert, dass die Verwendung von iter()
sicherer ist, da die alte Methode zur Implementierung der Iteration in Python auf __getitem__
basierte und der Ansatz mit isinstance()
das nicht erkennen würde. Dies mag bei älteren Python-Versionen zutreffend gewesen sein, aber basierend auf meinen ziemlich umfangreichen Tests funktioniert isinstance()
heutzutage großartig. Der einzige Fall, in dem isinstance()
nicht funktionierte, aber iter()
funktionierte, war mit UserDict
bei Verwendung von Python 2. Wenn das relevant ist, ist es möglich, isinstance(item, (Iterable, UserDict))
zu verwenden, um dies abzudecken.
Seit Python 3.5 können Sie das Typisierungs-Modul aus der Standardbibliothek für typbezogene Dinge verwenden:
from typing import Iterable
...
if isinstance(my_item, Iterable):
print(True)
Dies reicht nicht aus: Das Objekt, das von __iter__
zurückgegeben wird, muss das Iterationsprotokoll implementieren (d.h. die next
-Methode). Siehe den relevanten Abschnitt in der Dokumentation.
In Python ist es eine gute Praxis, "zu versuchen und zu sehen" anstatt "zu überprüfen".
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.