2016-06-28 8 views
2

Ich versuche eine Funktion zu erstellen, die ein Iterable akzeptiert und ein Tupel zurückgibt, vorausgesetzt, dass das Iterable immer in einer kanonischen Weise iteriert wird. Zum Beispiel, wenn die Eingabe iterable list oder tuple-Like ist, möchte ich die Eingabe akzeptieren, aber nicht, wenn es dict-Like (wo gibt es keine Garantie für die Reihenfolge der Schlüssel). Gibt es irgendeine Python-Funktion, um die Unterschiede zwischen Objekten zu erkennen, die immer in der gleichen Reihenfolge iteriert werden, im Vergleich zu denen, bei denen die Reihenfolge von Version zu Version geändert werden kann oder von PYTHONHASHSEED abhängt?Geordnete Iterables (Sequenzen) in Python erkennen

isinstance(x, collections.Sequence) macht das meiste von dem, was ich will, aber Generatoren sind keine Sequenzen. Der folgende Code scheint zu tun, was ich will, aber ich bin mir nicht sicher, ob ich etwas auslasse oder ob es einen allgemeineren Weg gibt, die Idee einer geordneten, aber nicht unbedingt indexierbaren, iterierbaren Idee einzufangen.

import collections, types 
def to_tuple(x): 
    if isinstance(x, collections.Sequence) or isinstance(x, types.GeneratorType): 
     return tuple(x) 
    raise Exception("Cannot be iterated canonically") 
+1

In Bezug auf Generatoren - Sie können nicht gehen über den gleichen Generator zum zweiten Mal in der gleichen Weise - also warum sollten Sie es aufnehmen wollen? –

+0

@AdamSosnowski Wenn das ein Problem ist, könnte ich 'itiltools.tee()' verwenden, um den Generator zuerst zu klonen, aber für meine Zwecke ist es egal, ob ich die ursprüngliche Eingabe verarbeite. –

Antwort

2

Es gibt keine solche Funktion. Auch bei Generatoren, würde wollen Sie in der Lage sein zu fangen

(x for x in {1, 2, 3}) 

aber erlauben

(x for x in [1, 2, 3]) 

würde ich empfehlen, nur eine Warnung, wenn type(x) is dict erhöhen. Nicht einmal isinstance(x, dict), weil OrderedDicts bestellt werden.

+1

Sie müssten auch 'set' und andere' dict' Unterklassen ausschneiden. Ich würde lieber alles ausschneiden, was von 'collections.Set' oder' collections.Mapping' erbt, es sei denn, es erbt auch von 'collections.OrderedDict'. Natürlich, wie Sie sehr gut darauf hingewiesen haben, ist es unmöglich, das perfekt zu machen. – mgilson

+0

@PadraicCunningham: Vielleicht ist Ihre Unterklasse bestellt! Selbst wenn Sie "collections.OrderedDict" als Spezialfall verwenden, verwenden Sie vielleicht Djangos altes ['SortedDict'] (https://code.djangoproject.com/wiki/SortedDict) oder das' SortedDict' von [SortedContainers] (https://pypi.python.org/pypi/sortedcontainers). Ich nehme an, Warnung auf 'type (x) in (dict, set, frozenset)' wäre eine gute Erweiterung. – user2357112

0

Möglicherweise möchten Sie überprüfen, ob das Schneiden Betrieb definiert:

def to_tuple(x): 
    return tuple(x[:]) 

Das Wörterbücher Regeln aus, Generatoren, sondern ausdrücklich erwünscht Strings, Tupel, Listen ...

+0

Und Downvote - warum? –

+1

Ich habe nicht downvote, aber ich glaube nicht, dass dies wirklich besser ist als 'isinstance (x, collections.Sequence)' was OP bereits abgelehnt hat, weil es keine Generatoren unterstützt. – mgilson

+0

Nun ... es testet das Verhalten anstelle der Vererbung. Zum Beispiel scheitern die "Sequence" Tests für numpy.darray und das Slicing ist erfolgreich. –