Ich habe eine Funktion, die ein Argument akzeptiert, das entweder ein einzelnes oder ein doppeltes Element sein kann:
def iterable(arg)
if #arg is an iterable:
print "yes"
else:
print "no"
damit:
>>> iterable (("f", "f")) Ja >>> iterierbar (["f", "f"]) Ja >>> iterable ("ff") Nein
Das Problem ist, dass die Zeichenfolge technisch iterierbar ist, sodass ich den ValueError beim Versuch nicht einfach abfangen kann arg[1]
. Ich möchte isinstance () nicht verwenden, da dies keine gute Praxis ist (oder wie mir gesagt wurde).
isinstance
ist die Möglichkeit, dies in dynamisch typisierten Sprachen zu tun. Eine Sache, die nicht jeden Tag verwendet werden darf, aber in berechtigten Fällen in Ordnung ist.Antworten:
Verwenden Sie isinstance (ich verstehe nicht, warum es schlechte Praxis ist)
Beachten Sie die Verwendung von StringTypes. Es stellt sicher, dass wir keine obskure Art von Zeichenfolge vergessen.
Auf der anderen Seite funktioniert dies auch für abgeleitete Zeichenfolgenklassen.
Vielleicht möchten Sie auch einen Blick auf diese vorherige Frage werfen .
Prost.
NB: Das Verhalten wurde in Python 3 geändert
StringTypes
undbasestring
ist nicht mehr definiert. Abhängig von Ihren Anforderungen können Sie sieisinstance
durchstr
oder ein Teilmengen-Tupel ersetzen(str, bytes, unicode)
, z. B. für Cython-Benutzer. Wie @Theron Luhn erwähnt hat, können Sie auch verwendensix
.quelle
isinstance
könnte der einzige Weg sein.do isinstance(arg, str)
. Für eine abwärtskompatible Version sollten Sie pythonhosted.org/six/#six.string_typestypes.StringTypes
, dass es in Python3 nicht verfügbar ist. Was ist der Wert in Python2?Ab 2017 ist hier eine tragbare Lösung, die mit allen Versionen von Python funktioniert:
quelle
Seit Python 2.6 mit der Einführung abstrakter Basisklassen
isinstance
(verwendet auf ABCs, keine konkreten Klassen) wird dies nun als vollkommen akzeptabel angesehen. Speziell:Dies ist eine exakte Kopie (die nur den Klassennamen ändert) von
Iterable
wie in_abcoll.py
(ein Implementierungsdetail voncollections.py
) definiert. Der Grund, warum dies so funktioniert, wie Sie es wünschencollections.Iterable
, ist, dass letzteres die Extrameile geht, um sicherzustellen, dass Zeichenfolgen vorhanden sind wird als iterabel angesehen, indemIterable.register(str)
explizit direkt nach dieserclass
Anweisung aufgerufen wird .Natürlich ist es einfach zu erweitern,
__subclasshook__
indem SieFalse
vor demany
Aufruf für andere Klassen zurückkehren, die Sie ausdrücklich von Ihrer Definition ausschließen möchten.In jedem Fall , nachdem Sie dieses neue Modul als importiert haben
myiter
,isinstance('ciao', myiter.NonStringIterable)
werdenFalse
, undisinstance([1,2,3], myiter.NonStringIterable)
wirdTrue
, wie Sie es fordern - und in Python 2.6 und höher ist dies der richtige Weg , so auszugestalten, Kontrollen betrachtet ... definieren eine abstrakte Basisklasse und überprüfeisinstance
es.quelle
isinstance('spam', NonStringIterable)
kehrt zurückTrue
.__iter__
ist jetzt in Python 3 in Strings implementiert ist. Mein "einfach zu erweiternder" Absatz wird also anwendbar und muss zBif issublass(cls, str): return False
zu Beginn hinzugefügt werden__subclasshook__
(sowie alle anderen Klassen, die__iter__
außer in Ihrem definieren Die Denkweise darf nicht als "Nicht-String-Iterable" akzeptiert werden.if issublass(C, str): return False
hinzugefügt werden sollte?Mir ist klar, dass dies ein alter Beitrag ist, aber ich dachte, es lohnt sich, meinen Ansatz für die Internet-Nachwelt hinzuzufügen. Die folgende Funktion scheint unter den meisten Umständen sowohl mit Python 2 als auch mit Python 3 für mich zu funktionieren:
Dies prüft, ob eine Nicht-Zeichenfolge durch (mis) Verwendung der integrierten Zeichenfolge iterierbar ist,
hasattr
wodurch a ausgelöst wird,TypeError
wenn das zweite Argument keine Zeichenfolge oder Unicode-Zeichenfolge ist.quelle
Durch das Kombinieren früherer Antworten verwende ich:
Kein 100% iger Narrenbeweis, aber wenn ein Objekt nicht iterierbar ist, können Sie es trotzdem passieren lassen und auf das Tippen von Enten zurückgreifen.
Bearbeiten: Python3
types.StringTypes == (str, unicode)
. Das Phython3-Äquivalent lautet:quelle
2.x.
Ich hätte vorgeschlagen:
oder angesichts des Kommentars von David Charles, der dies für Python3 optimiert, was ist mit:
3.x.
Der eingebaute abstrakte Typ 'basestring' wurde entfernt ( https://docs.python.org/3.0/whatsnew/3.0.html ). Verwenden Sie stattdessen 'str'. Die Typen 'str' und 'bytes' haben nicht genügend gemeinsame Funktionen, um eine gemeinsam genutzte Basisklasse zu gewährleisten.
quelle
__iter__
es in Python 3 Strings gibt?Wie Sie richtig hervorheben, ist eine einzelne Zeichenfolge eine Zeichenfolge.
Das, was Sie wirklich tun möchten, ist herauszufinden, welche Art von Sequenz
arg
ist, indem Sie isinstance oder type (a) == str verwenden.Wenn Sie eine Funktion realisieren möchten, die eine variable Anzahl von Parametern akzeptiert, sollten Sie dies folgendermaßen tun:
Funktion ("ff") und Funktion ("ff", "ff") funktionieren.
Ich kann kein Szenario sehen, in dem eine isiterable () - Funktion wie Ihre benötigt wird. Es ist nicht isinstance (), das einen schlechten Stil hat, sondern Situationen, in denen Sie isinstance () verwenden müssen.
quelle
type(a) == str
ist zu vermeiden. Dies ist eine schlechte Praxis, da ähnliche oder abgeleitete Typen nicht berücksichtigt werdenstr
.type
klettert nicht auf die Typhierarchie, während dies derisinstance
Fall ist, daher ist es besser, sie zu verwendenisinstance
.Um Alex Martellis hervorragenden Hack explizit zu erweitern
collections.py
und einige der damit verbundenen Fragen zu beantworten: Die derzeit funktionierende Lösung in Python 3.6+ istund demonstriert
Wenn Sie
iter('')
beispielsweise Ausschlüsse hinzufügen möchten , ändern Sie die Zeilesein
bekommen
quelle