2010-04-13 6 views
2

je dois retourner deux valeurs à la fois, donc je dois:Comment effectuer une itération sur les attributs de données d'un objet d'instance, en retournant deux valeurs à la fois?

class IterableObject(object): 
    def __iter__(self): 
    for item in self.__dict__: 
     return self.__dict__[item + 1], self.__dict__[item] 

Je peux donc avoir:

myObj1, myObj2 = IterableObject() 

value = myObj1.balance - myObj2.balance 

Bien sûr, il ne fonctionne pas. Qu'est-ce que je fais mal? Je pense que je ne peux pas ajouter de valeur sur un objet comme ça.

Répondre

5

Dans le itertools documentation il y a une fonction d'exemple appelé pairwise que vous pouvez copier dans votre projet:

def pairwise(iterable): 
    "s -> (s0,s1), (s1,s2), (s2, s3), ..." 
    a, b = tee(iterable) 
    next(b, None) 
    return izip(a, b) 

utiliser comme:

for x1, x2 in pairwise(some_iterable): 
    # etc.. 

Notez que lorsque vous itérer sur une dict les éléments ne sont pas nécessairement retournés dans l'ordre, donc vous devriez trier d'abord.

+0

merci, mais existe-t-il un moyen plus simple de le faire sans aller le chemin de itertools? – Spikie

1

Une solution possible sans itertools:

def pairwise(iterable): 
    it = iter(iterable) 
    try: 
     while True: 
      yield it.next(), it.next() 
    catch StopIteration: 
     pass 

>>> list(pairwise(range(6)) 
[(0, 1), (2, 3), (4, 5)] 
>>> list(pairwise(range(5)) 
[(0, 1), (2, 3)] 

Ceci est différent de la solution dans le itertools documentation en ce sens que le dernier élément est jamais revenu de itérable si elle arrive à contenir un nombre impair d'éléments. Mais je suppose que la solution dans les exemples itertools est meilleure.

1

Une légère modification de votre propre exemple devrait vous donner ce que vous voulez. Votre exemple d'origine montre que vous ne savez pas que l'itération sur un dictionnaire vous donne les clés du dictionnaire. "aproprty_name" + 1 ne vous donnera presque jamais ce que vous voulez.

class IterableObject: 
    def __iter__(self): 
    properties = (i for i in self.__dict__) 
    While True: 
     a = properties.next() 
     try: 
     b = properties.next() 
     except StopIteration: 
     yield (getattr(self,a),) #for the odd number of properties case 
     raise StopIteration 
     yield getattr(self, a), getattr(self, b) 

Cela ne fonctionnera pas dans l'exemple que vous présentez. Vous ne pouvez pas anticiper aveuglément les valeurs dans un ordre quelconque qui ferait que la soustraction de l'une à l'autre ait un sens.

Ce que vous voulez probablement, c'est un objet qui renvoie les deux valeurs suivantes à partir d'une liste de valeurs que vous savez être un nombre pair de valeurs. Vous devrez définir cette liste dans l'objet. De cette façon, la séquence appariée dans l'ordre serait renvoyée dans le même ordre.

class PairedList: 
    def __iter__(self): 
    balances = iter(self.balances) 
    while True: 
     yield balances.next(), balances.next() 

>>> b = PairedList() 
>>> b.balances = (2000, 151, 1000, 255, 600, 150, 0, 20, 30, 30, 50, 10) 
>>> [i for i in b] 
[(2000, 151), (1000, 255), (600, 150), (0, 20), (30, 30), (50, 10)] 
>>> [(balance-withdrawal, balance, withdrawal) for balance, withdrawal in b] 
[(1849, 2000, 151), (745, 1000, 255), (450, 600, 150), (-20, 0, 20), (0, 30, 30), (40, 50, 10)] 

Vous pouvez vous interroger et relire l'exemple et les reformuler parce que vous créez écrit un nouvel objet et attendre qu'il contient déjà vos valeurs. Un exemple en utilisant ma classe PairedList qui ferait cela pour vous serait:

>>> PairedList.balances = b.balances 
>>> [(balance-withdrawal, balance, withdrawal) for balance, withdrawal in PairedList()] 
[(1849, 2000, 151), (745, 1000, 255), (450, 600, 150), (-20, 0, 20), (0, 30, 30), (40, 50, 10)] 

Mais ce qui est presque certainement pas ce que vous voulez. Cela vous limiterait par défaut à n'avoir qu'un ensemble de soldes que vous pourriez parcourir. Et créer un ensemble de balances par défaut pour chaque objet PairedList qui finira par revenir vous mordre dans la crosse.