492 Stimmen

Wie kann man prüfen, ob ein Objekt eine Liste oder ein Tupel (aber keine Zeichenkette) ist?

Das ist es, was ich normalerweise tue, um sicherzustellen, dass es sich bei der Eingabe um eine list / tuple - aber nicht ein str . Denn oft bin ich über Bugs gestolpert, bei denen eine Funktion eine str Objekt versehentlich, und die Zielfunktion macht for x in lst unter der Annahme, dass lst ist eigentlich ein list o tuple .

assert isinstance(lst, (list, tuple))

Meine Frage lautet: Gibt es eine bessere Möglichkeit, dies zu erreichen?

328voto

Nick Craig-Wood Punkte 50398

Nur in Python 2 (nicht Python 3):

assert not isinstance(lst, basestring)

ist eigentlich das, was Sie wollen, sonst verpassen Sie viele Dinge, die sich wie Listen verhalten, aber keine Unterklassen von list o tuple .

174voto

steveha Punkte 70950

Erinnern Sie sich daran, dass wir in Python "Duck Typing" verwenden wollen. Das heißt, alles, was sich wie eine Liste verhält, kann als Liste behandelt werden. Prüfen Sie also nicht den Typ einer Liste, sondern nur, ob sie sich wie eine Liste verhält.

Aber auch Strings verhalten sich wie eine Liste, und das ist oft nicht das, was wir wollen. Es gibt Zeiten, in denen das sogar ein Problem ist! Prüfen Sie also explizit, ob es sich um eine Zeichenkette handelt, und verwenden Sie dann Duck-Typing.

Hier ist eine Funktion, die ich zum Spaß geschrieben habe. Es ist eine spezielle Version von repr() die eine beliebige Folge in spitzen Klammern ('<', '>') ausgibt.

def srepr(arg):
    if isinstance(arg, basestring): # Python 3: isinstance(arg, str)
        return repr(arg)
    try:
        return '<' + ", ".join(srepr(x) for x in arg) + '>'
    except TypeError: # catch when for loop fails
        return repr(arg) # not a sequence so just return repr

Das ist insgesamt sauber und elegant. Aber was ist das isinstance() Was macht der Check dort? Das ist ein ziemlicher Schnitzer. Aber es ist wichtig.

Diese Funktion ruft sich selbst rekursiv auf alles auf, was sich wie eine Liste verhält. Wenn wir die Zeichenkette nicht speziell behandeln würden, dann würde sie wie eine Liste behandelt und ein Zeichen nach dem anderen aufgeteilt werden. Aber dann würde der rekursive Aufruf versuchen, jedes Zeichen wie eine Liste zu behandeln - und es würde funktionieren! Sogar eine Zeichenkette mit nur einem Zeichen funktioniert wie eine Liste! Die Funktion würde sich selbst immer wieder rekursiv aufrufen, bis der Stapel überläuft.

Funktionen wie diese, die darauf angewiesen sind, dass jeder rekursive Aufruf die zu erledigende Arbeit aufschlüsselt, müssen Zeichenketten in Sonderzeichen umwandeln, weil man eine Zeichenkette nicht unter die Ebene einer einstelligen Zeichenkette aufschlüsseln kann, und selbst eine einstellige Zeichenkette verhält sich wie eine Liste.

Anmerkung: Die try / except ist der sauberste Weg, unsere Absichten auszudrücken. Wenn dieser Code jedoch zeitkritisch wäre, könnten wir ihn durch eine Art Test ersetzen, um zu sehen, ob arg ist eine Folge. Anstatt den Typ zu testen, sollten wir wahrscheinlich eher das Verhalten testen. Wenn es eine .strip() Methode ist es eine Zeichenkette, also keine Sequenz; andernfalls, wenn es indizierbar oder iterierbar ist, ist es eine Sequenz:

def is_sequence(arg):
    return (not hasattr(arg, "strip") and
            hasattr(arg, "__getitem__") or
            hasattr(arg, "__iter__"))

def srepr(arg):
    if is_sequence(arg):
        return '<' + ", ".join(srepr(x) for x in arg) + '>'
    return repr(arg)

EDIT: Ursprünglich hatte ich den obigen Text mit einem Scheck für __getslice__() aber ich habe festgestellt, dass in der collections Modul-Dokumentation ist die interessante Methode __getitem__() Das macht Sinn, denn auf diese Weise wird ein Objekt indiziert. Das scheint grundlegender zu sein als __getslice__() also habe ich das oben genannte geändert.

127voto

H = "Hello"

if type(H) is list or type(H) is tuple:
    ## Do Something.
else
    ## Do Something.

116voto

suzanshakya Punkte 3267

Python 3:

import collections.abc

if isinstance(obj, collections.abc.Sequence) and not isinstance(obj, str):
    print("`obj` is a sequence (list, tuple, etc) but not a string or a dictionary.")

Geändert in Version 3.3: Verschiebung des globalen Namespace von "Collections Abstract Base Classes" von abc a collections.abc Modul. Aus Gründen der Abwärtskompatibilität werden sie auch in diesem Modul bis zur Version 3.8 sichtbar sein, wenn es nicht mehr funktioniert.

Python 2:

import collections

if isinstance(obj, collections.Sequence) and not isinstance(obj, basestring):
    print "`obj` is a sequence (list, tuple, etc) but not a string or unicode or dictionary."

41voto

Cesar Punkte 4359

Python mit PHP-Flair:

def is_array(var):
    return isinstance(var, (list, tuple))

CodeJaeger.com

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.

Powered by:

X