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.