6
votes

Qu'est-ce qu'un bon moyen de décorer un itérateur de modifier la valeur avant la prochaine étape est appelée Python?

Je travaille sur un problème qui implique de valider un format à partir du correctif différent d'unified Diff.

Les variables dans le format intérieur peuvent couvrir plusieurs lignes à la fois. J'ai donc écrit un générateur qui tire chaque ligne et donne la variable Lorsqu'il est complet. p>

Pour éviter de réécrire cette fonction lors de la lecture d'un fichier DIFF unifié, j'ai créé un générateur pour désigner les caractères diff de la ligne avant de le transmettre au validateur de format interne. Cependant, je suis coincé dans une boucle infinie (à la fois dans le code et dans ma tête). J'ai résumé à un problème au code suivant. Je suis sûr qu'il y a une meilleure façon de le faire. Je ne sais tout simplement pas ce que c'est. P>

from collections import Iterable

def inner_format_validator(inner_item):
    # Do some validation to inner items
    return inner_item[0] != '+'

def inner_gen(iterable):
    for inner_item in iterable:
        # Operates only on inner_info type data
        yield inner_format_validator(inner_item)

def outer_gen(iterable):
    class DecoratedGenerator(Iterable):
        def __iter__(self):
            return self
        def next(self):
            # Using iterable from closure
            for outer_item in iterable:
                self.outer_info = outer_item[0]
                inner_item = outer_item[1:]
                return inner_item
    decorated_gen = DecoratedGenerator()
    for inner_item in inner_gen(decorated_gen):
        yield inner_item, decorated_gen.outer_info

if __name__ == '__main__':    
    def wrap(string):
        # The point here is that I don't know what the first character will be
        pseudo_rand = len(string)
        if pseudo_rand * pseudo_rand % 2 == 0:
            return '+' + string
        else:
            return '-' + string

    inner_items = ["whatever"] * 3
    # wrap screws up inner_format_validator
    outer_items = [wrap("whatever")] * 3
    # I need to be able to
    # iterate over inner_items
    for inner_info in inner_gen(inner_items):
        print(inner_info)
    # and iterate over outer_items
    for outer_info, inner_info in outer_gen(outer_items):
        # This is an infinite loop
        print(outer_info)
        print(inner_info)


0 commentaires

3 Réponses :


1
votes

Je pense que cela fera ce que vous avez voulu dire si vous modifiez la définition de la définition de la décoratedenerator à ceci: xxx

Votre version d'origine n'a jamais terminé car son suivant () méthode était apatride et retournerait la même valeur chaque fois que cela s'appelait. Vous n'avez pas besoin d'avoir une méthode suivante () du tout, cependant, vous pouvez implémenter __ iter __ () vous (comme je l'ai fait), puis tout fonctionne bien. < / p>


0 commentaires

2
votes

Je n'aime toujours pas cela beaucoup, mais au moins il est plus court et un peu plus pythonique: xxx pré>

[modifier] inner_gen () code> et OUTER_GEN () CODE> SANS IMAP et partiel: P>

def transmogrify(iter_of_iters, *transmogrifiers):
    for iters in iter_of_iters:
        yield (
            trans(each) if trans else each
                for trans, each in izip(transmogrifiers, iters)
        )

for outer, inner in transmogrify(imap(split, stuff), inner_format_validator, None):
    print inner, outer


2 commentaires

Merci pour l'exemple de Comment utiliser FuncTools.Partial . Les outils sont assez astucieux, mais je trouve cette solution un peu difficile à suivre. Y aurait-il des avantages de performance pour le faire de cette façon?


Un problème est l'argument déballage dans izip (* IMAP (Split, iTerble)) qui décompresse l'ensemble de la totalité en mémoire en mémoire. Consultez mon autre solution pour une alternative qui évite cela. Je pense que c'est assez pythonique.



2
votes

Je ferais quelque chose de plus simple, comme ceci:

import random

def create_item():
    return random.choice(('+', '-')) + random.choice(('foo', 'bar'))

random_items = (create_item() for s in xrange(10))
added_items = ((i[0], i[1:]) for i in random_items if i.startswith('+'))
valid_items = ((prefix, line) for prefix, line in added_items if 'foo' in line)

print list(valid_items)


1 commentaires

Je pense que le dernier exemple est ce que je cherche.