Bienvenue sur IndexError.

Ici vous pouvez poser des questions sur Python et le Framework Django.

Mais aussi sur les technos front comme React, Angular, Typescript et Javascript en général.

Consultez la FAQ pour améliorer vos chances d'avoir des réponses à vos questions.

somme d'attributs dans une liste d' objets et methode magique add

+1 vote

Je veux utiliser add pour obtenir la somme d' un attribut dans une liste d' objets:

class Transaction():

    def __init__(self,valeur,nom=None,date=None):
        self.valeur = valeur
        self.nom = nom
        self.date = date

    def __add__(self, *other):      

        somme = 0
        for bidul in other:
            somme += bidul.valeur
        somme += self.valeur
        return "somme = ",somme

a = Transaction(7,'sept')
b = Transaction(10,'dix')
c = Transaction(-23,'ouch')

total = a+b+c
print(total)

j'obtiens l'erreur:

TypeError: can only concatenate tuple (not "Transaction") to tuple

Pb de syntax ou d' approche ?

demandé 13-Mai par buffalo974 (2,540 points)

1 Réponse

+4 votes
 
Meilleure réponse

Il faut bien voir que 'a+b+c' est interprété comme '(a+b)+c'.
Ceci explique l'erreur que tu obtiens: '(a+b)' est le tuple '("sommme = ", 17)', qui ne s'additionne pas avec 'c'.

Autrement dit, __add__ est associé à l'opérateur binaire '+', donc dans ta signature '__add__(self, *other)', other ne contient toujours qu'un seul élément quand on utilise '+'.

Si tu veux que ça marche, il faut que __add__ renvoie un type que tu saches additionner avec une Transaction. Ca peut être une Transaction ou bien une autre classe qu'il reste à écrire.
Tout dépend de ce qui fait sens pour ton code.

répondu 14-Mai par bubulle (2,066 points)
sélectionné 14-Mai par buffalo974

j'ai suivi ton conseil, ça marche bien mais le code que j' ai pondu est crado

myglobal = 0
prems_deja_passe = False

def switch_prems():

    global prems_deja_passe
    prems_deja_passe = True
    return prems_deja_passe

class Transaction():

    def __init__(self,valeur,nom=None,date=None):
        self.valeur = valeur
        self.nom = nom
        self.date = date

    def __add__(self, *other):

        global myglobal
        global prems_deja_passe

        if prems_deja_passe == False:
            myglobal += self.valeur
            switch_prems()

        for bidul in other:

            print("self.valeur = ",self.valeur)         
            print("bidul.valeur = ",bidul.valeur)
            print("myglobal = ",myglobal)

            print("\n--------------------")
            myglobal += bidul.valeur

        x = Transaction(myglobal)
        print("objet x : ",x)
        print("\nx.valeur = ",x.valeur)
        return x

a = Transaction(501,'PRIME')
b = Transaction(2500,'SALAIRE')
c = Transaction(-10,'pq')
d = Transaction(-20,'resto')
e = Transaction(-50,'peage')
f = Transaction(-1010,'avion')
g = Transaction(-2010,'impot')
h = Transaction(-5010,'mega_joint_de_culasse')


total = a+b+c+d+e+f+g+h
print("total  :",total.valeur)

z = input("\n press Enter")

En effet, c'est dur de faire propre seulement avec la classe Transaction.
Ca me parait normal puisque Transaction n'est pas là pour désigner un groupe de transactions.

Si je devais le faire, ça pourrait ressembler à ce qui suit.
J'utilise une seconde classe, Total, qui représente justement mon groupe de transactions:

class Transaction:
    def __init__(self, valeur, nom=None, date=None):
        self.valeur = valeur
        self.nom = nom
        self.date = date

    def __add__(self, other):
        return Total(self.transactions + other.transactions)

    @property
    def transactions(self):
        return (self,)


class Total:
    def __init__(self, transactions):
        self.transactions = tuple(transactions)

    def __add__(self, other):
        return Total(self.transactions + other.transactions)

    @property
    def valeur(self):
        return sum(e.valeur for e in self.transactions)

j' obtiens AttributeError: 'list' object has no attribute 'valeur'
et je n' arrive pas a avoir ce qu'il se passe lorsque j' insere un print à l' interieur du add de Transaction ni de Total.
(j ai pas besoin de pdb ici)

Une remarque pour commencer : le code que j'ai proposé est juste une esquisse pour mettre en avant une manière de faire. Il ne faut pas s'étonner s'il n'est pas très robuste.

Pour ton erreur. Je ne sais pas comment tu as écrit ton test mais vu que le code que je propose ne crée pas de liste, j'imagine que c'est ton test qui en fait apparaître.

Chez moi, ceci fonctionne:

a = Transaction(2)
b = Transaction(3)
c = Transaction(5)
tot = a+b+c
print(tot.valeur)  # -> 10
...