Dynamisches Ersetzen der nächsten Methode in Python

~~ Möglicherweise haben Sie das Verhalten der for-Anweisung in Python falsch verstanden. Wenn Sie also eine Idee haben, warum, wäre ich Ihnen dankbar, wenn Sie mich wissen lassen könnten. ~~ Gelöst.

Vorbereitung

Iterator, der dreimal dieselbe Zeichenfolge zurückgibt

iter.py


# coding: utf-8

class Iterator(object):
    def __init__(self):
        self.counter = 3

    def __iter__(self):
        return self

    def next(self):
        self.counter -= 1
        if self.counter < 0:
            raise StopIteration
        return "Hurra!"

Bestätigung

>>> from iter import Iterator
>>> instance = Iterator()
>>> iterator = iter(instance)
>>> print iterator.next()
Hurra!
>>> print iterator.next()
Hurra!
>>> print iterator.next()
Hurra!
>>> print iterator.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "iter.py", line 13, in next
    raise StopIteration
StopIteration

für Aussage ist auch möglich

>>> for i in Iterator():
...     print i
...
Hurra!
Hurra!
Hurra!

Hauptthema

RunTimeIterator, derIterator erbt und die next -Methode ersetzt, nachdem die ursprüngliche Iteration bei der Initialisierung nur einmal vorgerückt wurde

iter.py


# coding: utf-8
class Iterator(object):
    def __init__(self):
        self.counter = 3

    def __iter__(self):
        return self

    def next(self):
        self.counter -= 1
        if self.counter < 0:
            raise StopIteration
        return "Hurra!"


class RunTimeIterator(Iterator):
    def __init__(self):
        super(RunTimeIterator, self).__init__()

        for i in self:
            print i
            break
        self.next = self.alter_next

    def alter_next(self):
        self.counter -= 1
        if self.counter < 0:
            raise StopIteration
        return "Es macht Spaß!"

Bestätigung

>>> from iter import RunTimeIterator
>>> instance = RunTimeIterator()
Hurra!
>>> iterator = iter(instance)
>>> print iterator.next()
Es macht Spaß!
>>> print iterator.next()
Es macht Spaß!
>>> print iterator.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "iter.py", line 28, in alter_next
    raise StopIteration
StopIteration

Wenn Sie dies nun mit einer for-Anweisung verschieben,

>>> for i in RunTimeIterator():
...     print i
...
Hurra!
Hurra!
Hurra!

Es funktioniert aus irgendeinem Grund nicht.

Warum?

~~ Ich weiß es nicht. Es scheint ein Problem zu sein, das auftritt, wenn Sie versuchen, die Methode "next" direkt zu ersetzen. Im obigen Beispiel funktioniert es normal, wenn Sie die zurückgegebene Zeichenfolge in der Instanzvariablen halten und ersetzen, und im Allgemeinen implementiert die Methode "next" eine andere Methode Es funktioniert gut, wenn Sie versuchen, es zurückzugeben und zu ersetzen. ~~

Wenn Sie die Funktion "next ()" des Einbaus verwenden, ohne die Methode "next" direkt aufzurufen, tritt tatsächlich das gleiche Phänomen wie bei der for-Anweisung auf.

>>> from iter import RunTimeIterator
>>> instance = RunTimeIterator()
Hurra!
>>> iterator = iter(instance)
>>> print next(iterator)
Hurra!
>>> print next(iterator)
Hurra!
>>> print next(iterator)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "iter.py", line 12, in next
    raise StopIteration
StopIteration

Das Verhalten der for-Anweisung scheint mit der Funktion next () kursiv geschrieben zu sein, ohne die Methode next des Iteratorobjekts direkt aufzurufen. Der Grund, warum die Funktion "next ()" überhaupt erst erstellt wurde, ist, dass Sie die Methode "next" nicht direkt aufrufen müssen, wie Sie "iter ()" und "len ()" verwenden, anstatt "iter" und "len" direkt aufzurufen. Es scheint, dass dies daran liegt (ist es außerdem zweckmäßig, es in Python3 in "next" umzubenennen?) [^ 1], so dass es anscheinend nicht empfohlen wird, die "next" -Methode der Instanz direkt aufzurufen.

Schließlich besteht das Problem darin, dass das integrierte "next ()" zum Zeitpunkt der Klassendefinition die "next" -Methode zurückgibt, nicht die "next" -Methode der Instanz zum Zeitpunkt der Iteration. Anscheinend wird die Iterator-Implementierung festgelegt, wenn die Klasse definiert wird [^ 2].

Selbst wenn Sie die "next" -Methode der Instanz ersetzen, wird sie nicht im eigentlichen Iterator wiedergegeben, und wenn Sie die "next" -Methode der Klasse direkt neu schreiben, funktioniert sie.

python


class RunTimeIterator(Iterator):
    def __init__(self):
        super(RunTimeIterator, self).__init__()

        for i in self:
            print i
            break
        # self.next = self.alter_next
        self.__class__.next = self.alter_next

    def alter_next(self):
        self.counter -= 1
        if self.counter < 0:
            raise StopIteration
        return "Es macht Spaß!"

Wenn Sie es jedoch auf Klassenebene ersetzen, sieht es natürlich so aus, wenn Sie zwei oder mehr Instanzen erstellen.

>>> from iter import RunTimeIterator
>>> for i in RunTimeIterator():
...     print i
...
Hurra!
Es macht Spaß!
Es macht Spaß!
>>> for i in RunTimeIterator():
...     print i
...
Es macht Spaß!
Es macht Spaß!
Es macht Spaß!

Lösung?

Die next-Methode kann nicht direkt ersetzt werden. Stellen Sie daher sicher, dass die next-Methode eine Implementierung einer anderen Methode zurückgibt, und ersetzen Sie diese, wenn Sie sie ersetzen möchten. Im folgenden Beispiel gibt die Methode "next" das Ergebnis der Methode "_next" zurück. Wenn Sie die Methode "next" ersetzen möchten, ersetzen Sie die Methode "_next".

class RunTimeIterator(Iterator):
    def __init__(self):
        super(RunTimeIterator, self).__init__()

        for i in self:
            print i
            break
        self._next = self.alter_next

    def next(self):
        """Echt`next`Es ist eine Methode, aber der Inhalt ist`_next`
        """
        return self._next()

    def _next(self):
        """Wesentlich`next`Methode

Als Ausgangszustand des Elternteils`next`Versuchen Sie, die Methode zu verwenden.
        `_next`Anstatt eine Methode zu definieren`__init__`Zu

        self._next = super(RunTimeIterator, self).next

Es ist das gleiche, auch wenn es geschrieben ist.
        """
        return super(RunTimeIterator, self).next()

    def alter_next(self):
        self.counter -= 1
        if self.counter < 0:
            raise StopIteration
        return "Es macht Spaß!"
>>> from iter import RunTimeIterator
>>> for i in RunTimeIterator():
...     print i
...
Hurra!
Es macht Spaß!
Es macht Spaß!
>>> for i in RunTimeIterator():
...     print i
...
Hurra!
Es macht Spaß!
Es macht Spaß!

Ursprünglich möchte ich einen Parser schreiben, der den dem Header entsprechenden Bereich aus einer Datei eines bestimmten Formats in mehreren Zeilen analysiert und dann nur die erforderlichen Daten für jede Zeile in einer Klasse abruft und zurückgibt, die "Datei" erbt, und die "nächste" Methode ersetzt. Ich bin auf dieses Problem gestoßen, als ich etwas ausprobiert habe.

Referenzlink

Recommended Posts

Dynamisches Ersetzen der nächsten Methode in Python
Im Python-Befehl zeigt Python auf Python3.8
Verwendung der Methode __call__ in der Python-Klasse
Dynamisches Definieren von Variablen in Python
So füllen Sie mit Python dynamisch Nullen aus
Verwendung der C-Bibliothek in Python
Lernen Sie das Entwurfsmuster "Vorlagenmethode" in Python
Ich habe die Methode der kleinsten Quadrate in Python ausprobiert
Lernen Sie das Entwurfsmuster "Factory Method" in Python
Weiter Python in C-Sprache
Zeichnen Sie Diagramme in Julia ... Überlassen Sie die Diagramme Python
Tipps zum Schreiben werden in Python kurz abgeflacht
Simplex-Methode (Einzelmethode) in Python
Private Methode in Python
So erhalten Sie die Dateien im Ordner [Python]
Versuchen Sie, die Monte-Carlo-Methode in Python zu implementieren
Ich möchte den Fortschritt in Python anzeigen!
So rufen Sie den n-ten größten Wert in Python ab
Ich habe versucht, die in Python installierten Pakete grafisch darzustellen
So erhalten Sie den Variablennamen selbst in Python
In Python sortieren. Lassen Sie uns als nächstes über den Algorithmus nachdenken.
So ermitteln Sie die Anzahl der Stellen in Python
Wie Sie das aktuelle Verzeichnis in Python in Blender kennen
Bestimmen Sie den Schwellenwert mithilfe der P-Tile-Methode in Python
Konvertieren Sie das Bild in .zip mit Python in PDF
Ich möchte in Python schreiben! (3) Verwenden Sie Mock
[Python] Erstellt eine Methode zum Konvertieren von Radix in 1 Sekunde
Verwendung des in Lobe in Python erlernten Modells
[Python] So geben Sie Listenwerte der Reihe nach aus
Um das Äquivalent von Rubys ObjectSpace._id2ref in Python zu tun
Ich möchte R-Datensatz mit Python verwenden
Python Open CV hat versucht, das Bild im Text anzuzeigen.
So löschen Sie stdout in Python
Finde Fehler in Python
Importieren Sie Skripte dynamisch in Python
Melden Sie sich auf der Website in Python an
Sprechen mit Python [Text zu Sprache]
Rufen Sie Methoden in Python dynamisch auf
Wie man in Python entwickelt
Das Unterdrücken von Methodenüberschreibungen in Python
Post an Slack in Python
Ich möchte die Variablen in der Python-Vorlagendatei ersetzen und in einer anderen Datei in Massenproduktion herstellen
[Python] So überprüfen Sie, ob der Schlüssel im Wörterbuch vorhanden ist
So debuggen Sie eine Standard-Python-Bibliothek in Visual Studio
Ändern Sie das Standardausgabeziel in eine Datei in Python
Verschiedene Methoden zur Berechnung der Ähnlichkeit zwischen Daten mit Python
Ich habe versucht "Wie man eine Methode in Python dekoriert"
Praktische Schreibmethode beim kontinuierlichen Anhängen an die Liste in Python
So erhalten Sie den letzten (letzten) Wert in einer Liste in Python
Ich habe versucht, die Mail-Sendefunktion in Python zu implementieren
Programmieren, um in der Welt zu kämpfen ~ 5-1
Programmierung, um in der Welt zu kämpfen ~ 5-5,5-6
Überlassen Sie die mühsame Verarbeitung Python
Programmieren, um in der Welt zu kämpfen 5-3
[Python] Wie man PCA mit Python macht
Abrufen der arXiv-API in Python
Konvertieren Sie Markdown in Python in PDF
Speichern Sie die Binärdatei in Python