it-swarm.com.de

Python: Prüfen Sie, ob ein Objekt eine Sequenz ist

Gibt es in Python eine einfache Möglichkeit zu erkennen, ob etwas keine Sequenz ist? Ich habe versucht, Folgendes zu tun: if x is not sequence, aber Python hat das nicht gefallen

50
nicotine

iter(x) erhöht eine TypeError, wenn x nicht wiederholt werden kann - aber diese Prüfung "akzeptiert" Sets und Wörterbücher, obwohl andere Nichtsequenzen wie None und Zahlen "abgelehnt" werden.

Auf der anderen Seite sind Strings (die die meisten Anwendungen eher "Einzelartikel" als Sequenzen berücksichtigen wollen) sind in Wirklichkeit Sequenzen (dh, jeder Test, sofern er nicht für Strings spezifiziert ist, wird bestätigen, dass dies der Fall ist). Daher reichen solche einfachen Prüfungen oft nicht aus.

In Python 2.6 und höher wurden abstrakte Basisklassen eingeführt, und neben anderen leistungsstarken Funktionen bieten sie eine bessere systematische Unterstützung für eine solche "Kategorienprüfung".

>>> import collections
>>> isinstance([], collections.Sequence)
True
>>> isinstance((), collections.Sequence)
True
>>> isinstance(23, collections.Sequence)
False
>>> isinstance('foo', collections.Sequence)
True
>>> isinstance({}, collections.Sequence)
False
>>> isinstance(set(), collections.Sequence)
False

Sie werden bemerken, dass Strings noch als "eine Sequenz" (da sind ) betrachtet werden, aber Sie bekommen zumindest Diktate und Ablenkungen. Wenn Sie Strings aus Ihrem Konzept von "Sein als Sequenzen" ausschließen möchten, können Sie collections.MutableSequence verwenden (dies schließt jedoch auch Tupel aus, die wie Strings Sequenzen sind, aber nicht veränderbar sind) oder explizit:

import collections

def issequenceforme(obj):
    if isinstance(obj, basestring):
        return False
    return isinstance(obj, collections.Sequence)

Nach Geschmack abschmecken und heiß servieren! -)

64
Alex Martelli

Ich denke, das folgende Code-Snippet macht, was Sie wollen:

def is_sequence(obj):
    return hasattr(type(obj), '__iter__')
9
Humoyun

Da Python die Duck-Typisierung "festhält", besteht eine der Methoden darin, zu prüfen, ob ein Objekt über eine Member-Methode (Methode) verfügt.

Eine Sequenz hat eine Länge, eine Sequenz von Elementen und unterstützt das Slicing [ doc ]. Also wäre es so:

def is_sequence(obj):
    t = type(obj)
    return hasattr(t, '__len__') and hasattr(t, '__getitem__')
    # additionally: and hasattr(t, '__setitem__') and hasattr(t, '__delitem__')

Dies sind alles spezielle Methoden, __len__() sollte die Anzahl der Elemente zurückgeben, __getitem__(i) sollte ein Element zurückgeben (in der Reihenfolge ist dies i -th Element, aber nicht mit Mapping), __getitem__(slice(start, stop, step)) sollte die Untersequenz zurückgeben und __setitem__ und __delitem__ wie erwartet. Dies ist ein solcher Vertrag, aber ob das Objekt dies tatsächlich tut oder nicht, hängt davon ab, ob das Objekt den Vertrag einhält oder nicht.

Hinweis dass die obige Funktion auch True für die Abbildung zurückgibt, z. dict, da das Mapping auch diese Methoden hat. Um dies zu überwinden, können Sie eine schwerere Arbeit ausführen:

def is_sequence(obj):
    try:
        len(obj)
        obj[0:0]
        return True
    except TypeError:
        return False

Aber meistens brauchen Sie das nicht, tun Sie einfach so, als ob das Objekt eine Sequenz wäre, und fangen Sie eine Ausnahme ein, wenn Sie möchten. Das ist mehr Pythonic.

5
fikr4n

Die Python 2.6.5-Dokumentation beschreibt die folgenden Sequenztypen: Zeichenfolge, Unicode-Zeichenfolge, Liste, Tupel, Puffer und XRANGE.

def isSequence(obj):
    return type(obj) in [str, unicode, list, Tuple, buffer, xrange]
5

Warum tust du das? Der normale Weg ist hier, eine bestimmte Art von Dingen (eine Sequenz oder eine Zahl oder ein dateiähnliches Objekt usw.) anzufordern und diese dann ohne Prüfung zu verwenden. In Python verwenden wir normalerweise keine Klassen, um semantische Informationen zu transportieren, sondern verwenden einfach die definierten Methoden (dies wird als "duck typing" bezeichnet). Wir bevorzugen auch APIs, bei denen wir genau wissen, was zu erwarten ist. Verwenden Sie Schlüsselwortargumente, eine Vorverarbeitung oder definieren Sie eine andere Funktion, wenn Sie die Funktionsweise einer Funktion ändern möchten.

0
Mike Graham

Für Python 3 und 2.6 und höher können Sie überprüfen, ob es sich um eine Unterklasse von collections.Sequence handelt:

>>> import collections
>>> isinstance(myObject, collections.Sequence)
True

In Python 3.7 müssen Sie collections.abc.Sequence verwenden (collections.Sequence wird in Python 3.8 entfernt):

>>> import collections.abc
>>> isinstance(myObject, collections.abc.Sequence)
True

Dies funktioniert jedoch nicht für duck-typisierte Sequenzen, die __len__() und __getitem__() implementieren, aber nicht (wie sie sollten) die Unterklasse collections.Sequence. Es funktioniert jedoch für alle integrierten Python-Sequenztypen: Listen, Tupel, Strings usw.

Während alle Sequenzen iterierbar sind, sind nicht alle iterierbaren Sequenzen Sequenzen (z. B. Sets und Wörterbücher sind iterierbar, jedoch keine Sequenzen). Die Überprüfung von hasattr(type(obj), '__iter__') gibt True für Wörterbücher und Sets zurück.

0
Al Sweigart