Définition attribut classe parente

Résolu
frison - Modifié le 20 juin 2024 à 11:38
mamiemando Messages postés 33294 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 30 septembre 2024 - 24 juin 2024 à 16:09

Salut à tous, une question existentielle.

J'ai quelques classes héritant d'une même classe mère (pas un singleton), cette classe mère ne doit donc pas être instanciée directement, uniquement via les classes en héritant.

Maintenant, cette classe mère à besoin de l'instance d'une autre classe, qui lui sert à travailler elle-même, mais aussi les classes dérivées.

D'après-moi, il n'y a pas 36 solutions, soit en définissant une variable de classe dans la classe mère, et jeter une erreur si non définie :
 

class Outils:
    def __str__(self):
        return 'outils !'

class Maman:
    outils = None
    def __init__(self):
        if not isinstance(self.outils, Outils):
            raise AttributeError('outils non défini ou invalide')

class Bob(Maman):
    pass

try:
    bob = Bob()
except Exception as e:
    print(e)

Maman.outils = Outils()
bob = Bob()
print(bob.outils)


Cela ne me convient pas trop, puisque cela oblige à avoir accès à Maman. On pourrait faire autrement en permettant d'utiliser un argument optionnel dans la classe Bob qui devra être défini via la 1ère instance de Bob.

class Outils:
    def __str__(self):
        return 'outils !'

class Maman:
    _outils = None
    def __init__(self, outils=None):
        if not isinstance(self._outils, Outils):
            if not isinstance(outils, Outils):
                raise AttributeError('outils doit être défini une 1ère fois')
        Maman._outils = outils
        self._outils = outils

class Bob(Maman):
    def __init__(self, outils=None):
        super().__init__(outils)

try:
    bob = Bob()
except Exception as e:
    print(e)

outils = Outils()
bob = Bob(outils)
bob2 = Bob()
print(bob2.outils)


Mais idem, je trouve que cela peut être compliqué lorsque les instances de Bob peuvent être créées partout dans une application et parfois pas dans le même ordre.

Une dernière solution qui pour moi serait la meilleure est d'instancier Outils dans un module réservé à cet effet, par ex. communs.py et que l'application instancie Outils dans ce fichier commun, ainsi Maman devrait simplement aller chercher cet objet dans le module commun.
Le seul bémol avec cette approche est que tout le monde peut avoir accès à cet objet Outils.

Comment faites-vous (feriez-vous) cela ?

Avez-vous une autre façon de faire ?

4 réponses

yg_be Messages postés 23235 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 30 septembre 2024 Ambassadeur 1 538
Modifié le 20 juin 2024 à 13:32

bonjour,

C'est la classe Maman qui a besoin d'une l'instance de Outil, ou bien chaque instance de Maman qui en a besoin?

Dans le premier cas:

class Outils:
    def __init__(self):
        print("un nouvel outil a été créé",self)

class Maman:
    _outils = Outils()
    print("un outil créé par maman")
    def __init__(self):
        print("nouvelle maman",self,self._outils)
class Bob(Maman):
    pass
print("start")
bob1=Bob()
bob2=Bob()
0

Salut, cela aurait pu être faisable, mais outils doit être aussi utilisé ailleurs (j'aurais dû le préciser), c'est pour cela que dans le très gros résumé que j'en ai fait, Outils est instancié hors de ces classes et que l'instanciation a de plus, besoin de paramètres qui ne sont pas connus par ces classes.

Merci de ta proposition =)

0
yg_be Messages postés 23235 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 30 septembre 2024 1 538 > frison
20 juin 2024 à 15:21
class Outils:
    def __init__(self):
        print("un nouvel outil a été créé",self)

class Maman:
    _outils = None
    print("un outil créé par maman")
    def __init__(self):
        print("nouvelle maman",self,Maman._outils)
    def voila_ton_outil(o):
        Maman._outils=o
class Bob(Maman):
    pass
print("start")
marteau=Outils()
Bob.voila_ton_outil(marteau)
bob1=Bob()
bob2=Bob()

Tu as plusieurs instances de Outils()?

Peut-être manque-t-il une classe plus globale.

0
frison > yg_be Messages postés 23235 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 30 septembre 2024
20 juin 2024 à 16:11

Non, il n'y a qu'un unique objet Outils utilisé par plusieurs classes, pour cela que ma 3ème idée était de partager cet objet via un module dédié exclusivement à cela et qui simplifie vraiment la chose.

Oui, pourquoi pas ajouter un niveau supérieur, genre une classe singleton qui serait instanciée dans le main, je vais creuser dans ce sens.
 

0
yg_be Messages postés 23235 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 30 septembre 2024 1 538 > frison
20 juin 2024 à 16:24

Pourquoi instancier Outils?

class Outils:
    info=None
class Maman:
    def __init__(self):
        print("nouvelle maman",self,Outils.info)
class Bob(Maman):
    pass
print("start")
bob0=Bob()
print("bob0:",bob0)
Outils.info="marteau"
print("bob0:",bob0)
bob1=Bob()
bob2=Bob()
0
frison > yg_be Messages postés 23235 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 30 septembre 2024
20 juin 2024 à 16:52

Outils est une classe comportant beaucoup de méthodes et données diverses, ce n'est pas juste un simple container, sinon en effet, ce serait bien plus simple =)

0
yg_be Messages postés 23235 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 30 septembre 2024 Ambassadeur 1 538
20 juin 2024 à 15:18

Pourquoi écris-tu que ta première solution "oblige à avoir accès à Maman"?

Tu peux, en ligne 19:

Bob.outils = Outils()
0

Ouais, mais non, là c'est vraiment trop crade ^^

0
yg_be Messages postés 23235 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 30 septembre 2024 1 538 > frison
20 juin 2024 à 19:59

Tu fais des objections émotionelles, sans décrire tes besoins et tes contraintes.

0
frison > yg_be Messages postés 23235 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 30 septembre 2024
22 juin 2024 à 18:01

Salut, ben je les ai indiqués mes besoins et contraintes dans mon sujet, et puis comme je l'ai signalé, il n'y a pas qu'une seule classe dérivée, et je ne peux savoir où sera inititiée la 1ère instance.

0
Whismeril Messages postés 19145 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 29 septembre 2024 919
20 juin 2024 à 16:44

Bonjour

si je comprends bien ton besoin, Outils a tout intérêt à être un singleton.

Ainsi tu peux l'appeler comme yg_be l'a proposé dans son message #1

S'il a déjà été instancié par un autre objet qui en avait besoin, tu récupèreras l'instance sinon tu la créera 


0

Salut,

je suis complètement d'accord, et je m'en vais rester avec un module en guise de singleton et tant pis si ce n'est pas « standard », en python, c'est parfaitement acceptable.

0
mamiemando Messages postés 33294 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 30 septembre 2024 7 788
20 juin 2024 à 17:31

Bonjour,

Personnellement j'ai du mal à comprendre ce que tu cherches à faire. Peux-tu clarifier ton besoin ?

Maintenant, cette classe mère à besoin de l'instance d'une autre classe, qui lui sert à travailler elle-même, mais aussi les classes dérivées.

Peux-tu clarifier ? Est-ce qu'un bon vieil héritage ne suffit pas ?

J'ai quelques classes héritant d'une même classe mère (pas un singleton), cette classe mère ne doit donc pas être instanciée directement, uniquement via les classes en héritant.

Pourquoi "donc ne doit pas être instanciée directement" ? Essayes-tu de faire une classe abstraite ?

Comme le dit Whismeril #8, en toute logique Outils devrait être un Singleton (cf #5). Y a-t'il une raison qui t'interdit d'en faire un singleton, et si oui laquelle ? Car à partir du moment où c'est un singleton, tu "l'instancies" dans les méthodes où tu en as besoin et tu n'as aucune raison {d'en hériter | de la mémoriser en attribut de classe/instance | de la passer en paramètre}. C'est l'un des intérêts des singletons.

Le seul cas pratique que je vois où une classe mère peut avoir besoin de connaître ses classes filles, c'est quand tu implémentes des plugins sous forme de classe et que tu veux que ton framework supporte des plugins tiers. Est-ce ton cas ? Si oui, je t'invite à regarder ce lien.

Bonne chance

0

Salut,

Non, Maman n'est pas une classe abstraite, et cette classe n'a nul besoin de connaître ses héritières.

Comme je viens de l'indiquer, je m'en vais rester au module singleton pour stocker l'instance de Outils.

Merci à tous de vos réponses =)

0
Whismeril Messages postés 19145 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 29 septembre 2024 919 > frison
22 juin 2024 à 20:13

cette classe mère ne doit donc pas être instanciée directement, uniquement via les classes en héritant.

Ça c'est typiquement la description d'une classe abstraite 

0
mamiemando Messages postés 33294 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 30 septembre 2024 7 788 > Whismeril Messages postés 19145 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 29 septembre 2024
24 juin 2024 à 16:09

Bonjour,

Juste pour clarifier, les trois notions ci-dessous sont distinctes, répondent à des besoins différents, et son non-exclusive.

  • Un singleton est une manière de garantir qu'une classe ne peut être qu'instanciée qu'une seule fois (voir ici). Si on l'instancie plusieurs fois, on obtient une référence sur la même instance.
  • Une classe abstraite implémente un sous-ensemble de ses méthodes ; tant qu'une classe possède au moins une méthode abstraite, la classe ne doit pas être instanciée, car si on appelle une méthode abstraite (non implémentée) le programme lèvera une exception. Certains langages (comme le C++ et le Java) interdisent d'instancier des classes abstraites.
  • Par défaut, une classe mère n'a aucune idée de quelles sont ses classes filles. Toutefois, Python permet au travers de la méthode __init_subclass__ (voir ici) d'enregistrer dans une classe mère ses classes filles, ce n'est donc pas le comportement par défaut.

Dans ton cas tu n'en as probablement besoin que des deux premières notions...

0