Verwenden von „in“, um ein Attribut von Python-Objekten in einem Array abzugleichen

StackOverflow https://stackoverflow.com/questions/683

  •  08-06-2019
  •  | 
  •  

Frage

Ich kann mich nicht erinnern, ob ich geträumt habe oder nicht, aber ich scheine mich daran zu erinnern, dass es eine Funktion gab, die so etwas ermöglichte wie:

foo in iter_attr(array of python objects, attribute name)

Ich habe mir die Dokumente angesehen, aber so etwas fällt nicht unter die offensichtlich aufgeführten Überschriften

War es hilfreich?

Lösung

Die Verwendung eines Listenverständnisses würde eine temporäre Liste erstellen, die Ihren gesamten Speicher beanspruchen könnte, wenn die durchsuchte Sequenz groß ist.Auch wenn die Sequenz nicht groß ist, bedeutet das Erstellen der Liste, dass die gesamte vorherige Sequenz durchlaufen wird in könnte mit der Suche beginnen.

Die temporäre Liste kann durch die Verwendung eines Generatorausdrucks umgangen werden:

foo = 12
foo in (obj.id for obj in bar)

Nun, solange obj.id == 12 kurz vor Beginn bar, wird die Suche schnell sein, auch wenn bar ist unendlich lang.

Wie @Matt vorgeschlagen hat, ist es eine gute Idee, es zu verwenden hasattr wenn eines der Objekte in bar kann fehlen id Attribut:

foo = 12
foo in (obj.id for obj in bar if hasattr(obj, 'id'))

Andere Tipps

Möchten Sie eine Liste von Objekten erhalten, die ein bestimmtes Attribut haben?Wenn ja, a Listenverständnis ist der richtige Weg, dies zu tun.

result = [obj for obj in listOfObjs if hasattr(obj, 'attributeName')]

Du könntest immer selbst eines schreiben:

def iterattr(iterator, attributename):
    for obj in iterator:
        yield getattr(obj, attributename)

funktioniert mit allem, was iteriert, sei es ein Tupel, eine Liste oder was auch immer.

Ich liebe Python, es macht solche Dinge sehr einfach und macht nicht mehr Ärger als nötig, und in der Anwendung sind solche Dinge äußerst elegant.

Nein, du hast nicht geträumt.Python verfügt über ein ziemlich hervorragendes Listenverständnissystem, mit dem Sie Listen recht elegant manipulieren können, und je nachdem, was Sie genau erreichen möchten, kann dies auf verschiedene Arten erfolgen.Im Wesentlichen sagen Sie „Für Element in der Liste, wenn Kriterien.übereinstimmt“, und von da aus können Sie einfach die Ergebnisse durchlaufen oder die Ergebnisse in einer neuen Liste speichern.

Ich werde ein Beispiel daraus zitieren Tauchen Sie ein in Python hier, weil es ziemlich elegant ist und sie schlauer sind als ich.Hier erhalten sie eine Liste von Dateien in einem Verzeichnis und filtern dann die Liste nach allen Dateien, die einem regulären Ausdruckskriterium entsprechen.

    files = os.listdir(path)                               
    test = re.compile("test\.py$", re.IGNORECASE)          
    files = [f for f in files if test.search(f)]

Sie könnten dies in Ihrem Beispiel ohne reguläre Ausdrücke für alles tun, bei dem Ihr Ausdruck am Ende für eine Übereinstimmung „true“ zurückgibt.Es gibt andere Optionen wie die Verwendung der Funktion filter(), aber wenn ich wählen würde, würde ich diese wählen.

Eric Sipple

Die Funktion, an die Sie denken, ist wahrscheinlich operator.attrgettter.So erhalten Sie beispielsweise eine Liste, die den Wert des „id“-Attributs jedes Objekts enthält:

import operator
ids = map(operator.attrgetter("id"), bar)

Wenn Sie überprüfen möchten, ob die Liste ein Objekt mit einer ID == 12 enthält, dann ist ein ordentliches und effizientes (d. h.iteriert nicht unnötigerweise die gesamte Liste. Die Vorgehensweise ist:

any(obj.id == 12 for obj in bar)

Wenn Sie „in“ mit attrgetter verwenden und gleichzeitig die verzögerte Iteration der Liste beibehalten möchten:

import operator,itertools
foo = 12
foo in itertools.imap(operator.attrgetter("id"), bar)

Was ich mir vorgestellt habe, lässt sich mithilfe von Listenverständnissen erreichen, aber ich dachte, dass es eine Funktion gibt, die dies auf etwas übersichtlichere Weise erledigt.

d.h.„bar“ ist eine Liste von Objekten, die alle das Attribut „id“ haben.

Der mythische funktionale Weg:

foo = 12
foo in iter_attr(bar, 'id')

Der Weg zum Listenverständnis:

foo = 12
foo in [obj.id for obj in bar]

Rückblickend ist die Art und Weise des Listenverständnisses ohnehin ziemlich ordentlich.

Wenn Sie vorhaben, nach etwas einigermaßen anständigem Umfang zu suchen, verwenden Sie am besten ein Wörterbuch oder ein Set.Andernfalls müssen Sie grundsätzlich jedes Element des Iterators durchlaufen, bis Sie zu dem gewünschten Element gelangen.

Wenn es sich nicht unbedingt um leistungsempfindlichen Code handelt, sollte die Methode des Listenverständnisses funktionieren.Beachten Sie jedoch, dass es ziemlich ineffizient ist, da es jedes Element des Iterators durchgeht und es dann noch einmal durchgeht, bis es das Gesuchte findet.

Denken Sie daran, dass Python über einen der effizientesten Hashing-Algorithmen verfügt, die es gibt.Nutzen Sie es zu Ihrem Vorteil.

Ich finde:

#!/bin/python
bar in dict(Foo)

Ist das, woran Sie denken.Wenn Sie herausfinden möchten, ob ein bestimmter Schlüssel in einem Wörterbuch in Python (Pythons Version einer Hash-Tabelle) vorhanden ist, gibt es zwei Möglichkeiten, dies zu überprüfen.Erstens ist das has_key() Methode, die dem Wörterbuch beigefügt ist, und zweitens das oben angegebene Beispiel.Es wird ein boolescher Wert zurückgegeben.

Das sollte Ihre Frage beantworten.

Und jetzt etwas abseits des Themas, um dies in Zusammenhang zu bringen Listenverständnis Antwort zuvor gegeben (für etwas mehr Klarheit). Verständnis auflisten Erstellen Sie eine Liste aus einer einfachen Liste for-Schleife mit Modifikatoren.Als Beispiel (zur leichten Verdeutlichung) eine Möglichkeit, das zu verwenden in dict Sprachkonstrukt in a Listenverständnis:

Angenommen, Sie haben ein zweidimensionales Wörterbuch foo und Sie möchten nur die Wörterbücher der zweiten Dimension, die den Schlüssel enthalten bar.Ein relativ einfacher Weg, dies zu tun, wäre die Verwendung von a Listenverständnis mit einer Bedingung wie folgt:

#!/bin/python
baz = dict([(key, value) for key, value in foo if bar in value])

Beachten Sie das if bar in value Am Ende der Anweisung** handelt es sich um eine modifizierende Klausel, die Folgendes angibt Listenverständnis um nur die Schlüssel-Wert-Paare beizubehalten, die die Bedingung erfüllen.** In diesem Fall baz ist ein neues Wörterbuch, das nur die Wörterbücher von foo enthält, die bar enthalten (Hoffentlich habe ich in diesem Codebeispiel nichts verpasst ...Möglicherweise müssen Sie einen Blick auf die Dokumentation zum Listenverständnis werfen, die Sie in finden docs.python.org-Tutorials und bei secnetix.de, beide Seiten sind gute Referenzen, wenn Sie in Zukunft Fragen haben.).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top