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.

Modifier un attribut dynamique d'un objet à chaque instanciation d'un autre objet de même classe

+4 votes

Soit la classe suivante :

class Joueur:

    liste_joueurs = []

    def __init__(self):
        Joueur.liste_joueurs.append(self)
        self.nbr_joueurs = len(Joueur.liste_joueurs)

J'aimerais que l'attribut nbr_joueurs soit modifié pour chaque objet de type Joueur à chaque fois que j'en instancie un. Pour les besoins de mon programme, cet attribut ne peut pas être statique.
Exemple :

>>> a, b, c = Joueur(), Joueur(), Joueur()
>>> a.nbr_joueurs

Retourne 1 alors que je voudrais 3.

J'ai essayé :

>>> a, b, c = Joueur(), Joueur(), Joueur()
>>> a, b, c = Joueur(), Joueur(), Joueur()
>>> a.nbr_joueurs

Mais logiquement ça retourne 4.
On pourrait modifier init comme il suit :

def __init__(self):
    if self not in Joueur.liste_joueurs:
        Joueur.liste_joueurs.append(self)
    self.nbr_joueurs = len(Joueur.liste_joueurs)

Mais ça ne supprime pas le besoin de lancer deux fois la méthode init de chaque objet.

demandé 20-Avr par Aristote (166 points)

Pourquoi ne pas en faire une méthode ?

def nbr_joueurs():
    return len(Joueur.liste_joueurs)

2 Réponses

+5 votes
 
Meilleure réponse

J'avoue que j'ai du mal à comprendre...

1) Quelle contrainte t'oblige sincèrement à ne pas utiliser de variable de classe alors que tu en utilises déjà une dans ton exemple ?

nombre_joueurs = len(Joueur.liste_joueurs)

2) Si cette variable de classe existe, pourquoi ne pas tout simplement faire de nbr_joueurs une propriété qui va chercher la donnée ?

class Joueur:
    liste_joueurs = []

    @property
    def nbr_joueurs(self):
        return len(Joueur.liste_joueurs)

3) Je ne comprends pas ton problème de double appel de l'initialisateur, pour moi ça devrait fonctionner comme attendu.

In [1]: class O:
   ...:     l = []
   ...:     def __init__(s, *a, **kw):
   ...:         if s not in O.l:
   ...:             O.l.append(s)
   ...:         super().__init__(*a, **kw)
   ...:

In [2]: o1, o2, o3 = O(), O(), O()

In [3]: len(O.l)
Out[3]: 3

Bref, nous manquons de détails pour pouvoir t'aider correctement. ;)

répondu 20-Avr par debnet (990 points)
sélectionné 21-Avr par Aristote

1) L'attribut d'instance nbrjoueurs doit être réinitialisé à chaque instanciation d'un objet Joueur mais doit pouvoir ensuite évoluer indépendament dans chaque objet.
2) Oui en effet, ça semble être une bonne solution.
3) Je pensais lancer deux fois la méthode init (une fois à la création de l'objet et une fois tous les objets créés) pour mettre à jour l'attribut self.nbr
joueurs en fonction de Joueur.liste_joueur.

+3 votes

dans joueur.py:

class Joueur:
    joueurs = []

    def __init__(self):
        Joueur.joueurs.append(self)

    @property
    def nb(self):
        return len(Joueur.joueurs) 

Exemple d'usage:

>>> from joueur import Joueur
>>> Joueur.nb
<property object at 0x7fd2194e10e8>
>>> a, b, c = Joueur(), Joueur(), Joueur()
>>> a.nb
3
>>> a, b, c = Joueur(), Joueur(), Joueur()
>>> a.nb
6
>>> a.joueurs
[<joueur.Joueur object at 0x7fd21b22b358>, <joueur.Joueur object at 0x7fd21b22b400>, <joueur.Joueur object at 0x7fd21b22b4a8>, <joueur.Joueur object at 0x7fd2194e0908>, <joueur.Joueur object at 0x7fd2194e0940>, <joueur.Joueur object at 0x7fd2194e0978>]
>>> a.joueurs.pop()   # renvoie et supprime le dernier joueur de la liste
<joueur.Joueur object at 0x7fd2194e0978>
>>> a.nb
5
répondu 20-Avr par glickind (196 points)
...