Pour remplacer dynamiquement la méthode suivante en python

~~ Vous avez peut-être mal compris le comportement de l'instruction for en python, donc si vous avez une idée de pourquoi, je vous serais reconnaissant de bien vouloir me le faire savoir. ~~ Résolu.

Préparation

Itérateur qui renvoie la même chaîne trois fois

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 "Hourra!"

Vérification

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

pour la déclaration est également possible

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

Sujet principal

RunTimeIterator qui hérite de ʻIterator et remplace la méthode next` après avoir avancé l'itération d'origine une seule fois à l'initialisation

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 "Hourra!"


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 "C'est marrant!"

Vérification

>>> from iter import RunTimeIterator
>>> instance = RunTimeIterator()
Hourra!
>>> iterator = iter(instance)
>>> print iterator.next()
C'est marrant!
>>> print iterator.next()
C'est marrant!
>>> 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

Maintenant, si vous déplacez ceci avec une instruction for,

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

Cela ne fonctionne pas pour une raison quelconque.

Pourquoi?

~~ Je ne sais pas. Cela semble être un problème qui se produit lorsque vous essayez de remplacer directement la méthode next, dans l'exemple ci-dessus, cela fonctionne normalement si vous maintenez la chaîne de caractères retournée dans la variable d'instance et la remplacez, et plus généralement la méthode next implémente une autre méthode Cela fonctionne bien si vous essayez de le retourner et de le remplacer. ~~

En fait, si vous utilisez la fonction next () du build-in sans appeler directement la méthode next, le même phénomène que l'instruction for se produit.

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

Quant au comportement de l'instruction for, il semble qu'il soit mis en italique en utilisant la fonction next () sans appeler directement la méthode next de l'objet itérateur. La raison pour laquelle la fonction next () a été créée en premier lieu est que vous n'avez pas à appeler la méthode next directement comme vous utilisez ʻiter ()oulen ()au lieu d'appeleriter ou lendirectement. Il semble que ce soit à cause de cela (en plus, est-il pratique de le renommer ennext en python3?) [^ 1], il semble donc qu'il n'est pas recommandé d'appeler directement la méthode next` de l'instance.

Après tout, le problème est que la méthode intégrée next () renvoie la méthode next au moment de la définition de la classe, pas la méthode next de l'instance au moment de l'itération. Apparemment, l'implémentation de l'itérateur est définie lorsque la classe est définie [^ 2].

Même si vous remplacez la méthode next de l'instance, elle ne sera pas reflétée dans l'itérateur réel, et si vous réécrivez directement la méthode next de la classe, cela fonctionnera.

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 "C'est marrant!"

Cependant, si vous le remplacez au niveau de la classe, il en sera bien sûr ainsi lorsque vous créerez deux ou plusieurs instances.

>>> from iter import RunTimeIterator
>>> for i in RunTimeIterator():
...     print i
...
Hourra!
C'est marrant!
C'est marrant!
>>> for i in RunTimeIterator():
...     print i
...
C'est marrant!
C'est marrant!
C'est marrant!

Solution?

La méthode next ne peut pas être remplacée directement, donc assurez-vous que la méthode next renvoie une implémentation d'une autre méthode, et remplacez-la lorsque vous souhaitez la remplacer. Dans l'exemple suivant, la méthode next renvoie le résultat de la méthode _next et lorsque vous souhaitez remplacer la méthode next, vous remplacez la méthode _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):
        """Réel`next`C'est une méthode, mais le contenu est`_next`
        """
        return self._next()

    def _next(self):
        """Substantiel`next`Méthode

Comme état initial du parent`next`Essayez d'utiliser la méthode.
        `_next`Au lieu de définir une méthode`__init__`À

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

C'est la même chose même si c'est écrit.
        """
        return super(RunTimeIterator, self).next()

    def alter_next(self):
        self.counter -= 1
        if self.counter < 0:
            raise StopIteration
        return "C'est marrant!"
>>> from iter import RunTimeIterator
>>> for i in RunTimeIterator():
...     print i
...
Hourra!
C'est marrant!
C'est marrant!
>>> for i in RunTimeIterator():
...     print i
...
Hourra!
C'est marrant!
C'est marrant!

À l'origine, je souhaite écrire un analyseur qui analyse la zone correspondant à l'en-tête à partir d'un fichier d'un certain format, puis ne récupère que les données nécessaires pour chaque ligne avec une classe qui hérite de file, et remplace la méthode next. J'ai rencontré ce problème lorsque j'essayais quelque chose.

Lien de référence

Recommended Posts

Pour remplacer dynamiquement la méthode suivante en python
Dans la commande python, python pointe vers python3.8
Comment utiliser la méthode __call__ dans la classe Python
Comment définir dynamiquement des variables en Python
Comment remplir dynamiquement des zéros avec Python
Comment utiliser la bibliothèque C en Python
Apprenez le modèle de conception "Méthode de modèle" en Python
J'ai essayé la méthode des moindres carrés en Python
Apprenez le modèle de conception "Méthode d'usine" en Python
Next Python en langage C
Dessinez des graphiques dans Julia ... Laissez les graphiques à Python
Conseils pour rédiger un aplatissement concis en python
Méthode Simplex (méthode unique) en Python
Méthode privée en python
Comment obtenir les fichiers dans le dossier [Python]
Essayez d'implémenter la méthode Monte Carlo en Python
Je veux afficher la progression en Python!
Comment récupérer la nième plus grande valeur en Python
J'ai essayé de représenter graphiquement les packages installés en Python
Comment obtenir le nom de la variable lui-même en python
Trier en Python. Pensons ensuite à l'algorithme.
Comment obtenir le nombre de chiffres en Python
Comment connaître le répertoire actuel en Python dans Blender
Déterminer le seuil à l'aide de la méthode P-tile en python
Convertissez l'image au format .zip en PDF avec Python
Je veux écrire en Python! (3) Utiliser des simulacres
[Python] Création d'une méthode pour convertir la base en 1 seconde
Comment utiliser le modèle appris dans Lobe en Python
[Python] Comment afficher les valeurs de liste dans l'ordre
Pour faire l'équivalent de Ruby ObjectSpace._id2ref en Python
Je veux utiliser le jeu de données R avec python
Python Open CV a essayé d'afficher l'image sous forme de texte.
Pour vider stdout en Python
Trouver des erreurs en Python
Importer dynamiquement des scripts en Python
Connectez-vous au site Web en Python
Parler avec Python [synthèse vocale]
Appeler dynamiquement des méthodes en Python
Comment développer en Python
Suppression des substitutions de méthode en Python
Publier sur Slack en Python
Je veux remplacer les variables dans le fichier de modèle python et le produire en masse dans un autre fichier
[python] Comment vérifier si la clé existe dans le dictionnaire
Comment déboguer une bibliothèque Python standard dans Visual Studio
Changer la destination de sortie standard en un fichier en Python
Différentes façons de calculer la similitude entre les données avec python
J'ai essayé "Comment obtenir une méthode décorée en Python"
Méthode d'écriture pratique lors de l'ajout continu à la liste en Python
Comment obtenir la dernière (dernière) valeur d'une liste en Python
J'ai essayé d'implémenter la fonction d'envoi de courrier en Python
Programmation pour combattre dans le monde ~ 5-1
Programmation pour combattre dans le monde ~ 5-5,5-6
Laissez le traitement gênant à Python
Programmer pour combattre dans le monde 5-3
[Python] Comment faire PCA avec Python
Obtenir l'API arXiv en Python
Convertir Markdown en PDF en Python
Enregistrez le fichier binaire en Python