Salut !
En python je sais rajouter des attributs à un objet qu'il n'a pas dans sa classe, mais je sais pas faire pour les méthodes.
Discussion :
Salut !
En python je sais rajouter des attributs à un objet qu'il n'a pas dans sa classe, mais je sais pas faire pour les méthodes.
Bonsoir,
Dans tous les cas, au moins en Python 3, tu peux assigner un attribut à une classe ou à une instance de classe, soit directement, soit à l'aide de setattr()
Code python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 target.attribut = valeur setattr(target, "attribut", valeur)
Mais si tu en arrives là, c'est qu'il y a probablement une erreur de conception dans ton approche et c'est elle qu'il faut corriger avant d'aller plus loin, à commencer pour éviter de prendre de mauvaises habitudes dès le départ. Cela dit, il y a trois manières de faire :
1. Ajouter un attribut lambda à une instance de classe
Tu peux ajouter une fonction lambda en tant qu'attribut d'instance. Mais comme celle-ci n'appartiendra qu'à cette instance et donc pas aux autres objets du même type, elle se comportera comme une fonction ordinaire et ne recevra pas le paramètre self. Elle ne pourra donc pas accéder aux autres attributs de l'instance de ta classe :
Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 class MaClasse: def MethodeUne(self): print("Méthode une -", self) ma_classe = MaClasse() setattr(ma_classe, "MethodeDeux", lambda self: print("Methode deux -", self)) # via setattr() ma_classe.MethodeDeux = lambda self: print("Methode deux -", self) # par assignation directe ma_classe.MethodeUne() # Methode une - <__main__.MaClasse object at 0x7fc2c8691400> ma_classe.MethodeDeux() # Ne fonctionnera pas ma_classe.MethodeDeux(None) # Methode deux - None
2. Ajouter un attribut lambda à la définition de la classe
Il est possible d'intervenir directement sur l'objet global servant de prototype de classe et à instancier les autres. Cependant, cela revient en fait à redéfinir la classe. Les méthodes que tu vas ajouter seront considérées comme en faisant partie et recevront donc le paramètre self. En revanche, elles vont devenir communes à toutes les instances de ta classe, y compris celles qui sont apparues avant que tu effectues ces modifications.
Dans l'exemple suivant, on déclare une première instance a et on essaie d'appeler les deux méthodes. La première fonctionne mais la seconde n'existe pas encore. Par la suite, on instancie b puis on modifie la définition de la classe pour lui ajouter une méthode. On s'aperçoit alors qu'il est devenu possible d'appeler MethodeDeux() aussi depuis a que b :
Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 class MonAutreClasse: def MethodeUne(self): print("Méthode une -", self) a = MonAutreClasse() a.MethodeUne() # Méthode une - <__main__.MonAutreClasse object at 0x7f4a10195400> a.MethodeDeux() # Ne fonctionnera pas b = MonAutreClasse() setattr(MonAutreClasse, "MethodeDeux", lambda self: print("Methode deux -", self)) # via setattr() MonAutreClasse.MethodeDeux = lambda self: print("Methode deux -", self) # par assignation directe a.MethodeUne() # Méthode une - <__main__.MonAutreClasse object at 0x7f4a10195400> a.MethodeDeux() # Methode deux - <__main__.MonAutreClasse object at 0x7f4a10195400> b.MethodeUne() # Méthode une - <__main__.MonAutreClasse object at 0x7f4a1017ce10> b.MethodeDeux() # Methode deux - <__main__.MonAutreClasse object at 0x7f4a1017ce10>
3. Dériver la classe
La dérivation de classe est la vraie voie à suivre, c'est un des piliers de la programmation orientée objet et c'est même la seule que te laisseront suivre certains langages. Les approches ci-dessus ne fonctionneront que si le langage est permissif et interprété (c'est utilisable en Javascript par exemple) mais pas avec du typage fort ni si le langage est compilé. Typiquement : elles ne fonctionneront pas en C++.
Dans l'exemple suivant, on définit non pas une mais deux classes. Une première classe « A » et une seconde classe « B » qui dérive de A. Donc, de la même façon qu'un « ChatAngora » est implicitement un « Chat », notre classe B sera implicitement une A dotée d'éléments supplémentaires. Les objets de type B pourront être passés partout où l'on attend un type A, mais l'inverse ne sera pas vraie.
C'est d'ailleurs là l'origine du mot « classe », qui doit en fait se comprendre comme « classification du règne animal », par exemple.
Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 class A: def MethodeUne(self): print("Méthode une -", self) class B(A): def MethodeDeux(self): print("Méthode deux -", self) a = A() b = B() a.MethodeUne() # Méthode une - <__main__.A object at 0x7f7d5c091550> a.MethodeDeux() # Ne fonctionnera pas b.MethodeUne() # Méthode une - <__main__.B object at 0x7f7d5c091400> b.MethodeDeux() # Méthode deux - <__main__.B object at 0x7f7d5c091400>
Merci beaucoup pour ta réponse qui est approfondie et j'ai bien appris grace à cela.
Ce que j'ai fait en fait c'est une classe de vaisseaux, qui est dérivée d'une classe principale, et de cette classe dérivée, je tire deux instances, mais la deuxième instance doit avoir une méthode que la première instance n'a pas, c'est à dire que la méthode nouvelle n'est pas dans la classe dérivée.
j'espère que je suis assez clair, lol
Je veux faire ça car le premier des deux vaisseaux de la classe dérivée, tire un missile.
Tandis que le deuxième tire deux boulets en même temps (un à gauche et un à droite) et pour ça j'ai besoin que ce deuxième vaisseau ait sa propre méthode donc.
Peut-être regarder du côté des méthodes abstraites (https://www.docstring.fr/glossaire/classe-abstraite/)
ou alors tu rajoutes une couche d'héritage par catégorie de vaisseaux
parce que tes 2 vaisseaux tirent, mais pas de la même façon (même fonction mais pas même contenu, donc éventuellement paramètre/objet différent passé à la fonction)
D'accord, tu es donc en train d'écrire un shoot'em up.
En théorie, cela signifierait donc que la deuxième instance est elle-même une classe dérivée de la classe dérivée. Rien ne t'empêche de dériver les classes à l'infini, mais il faut se souvenir qu'il s'agit à chaque fois d'un nouveau type, donc il vaut mieux le faire lorsque c'est réellement nécessaire. Cela dit, tu obtiendrais le diagramme suivant :Ce que j'ai fait en fait c'est une classe de vaisseaux, qui est dérivée d'une classe principale, et de cette classe dérivée, je tire deux instances, mais la deuxième instance doit avoir une méthode que la première instance n'a pas, c'est à dire que la méthode nouvelle n'est pas dans la classe dérivée.
Code Texte : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6+--- Vaisseau lance-missile | ClassePrincipale <--- Vaisseau <--+ | +--- Vaisseau lance-boulets
En réalité, l'approche la plus intelligente ici consiste en fait à déclarer des classes pour les armes en particulier :
Code Texte : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6+--- Lance-missile | Arme <--+ | +--- Lance-boulets
… et de prévoir un champ « arme » dans la classe « Vaisseau » :
Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 class Vaisseau: arme = None
Bonjour à tous,
En complément, si je reprends votre première discussion et votre méthode tirer(), j'y vois un argument arme et donc vous sembler vouloir gérer ce cas au niveau de cette méthode tirer() ?
Après il faut voir bien sûr si ça peut se gérer uniquement à ce niveau là, peut-être en définissant le type de tir à l'aide d'un attribut type_tir au moment de la création de l'objet. Et sinon les propositions qui ont été faites me semblent aussi valables.
Cdlt
Vous trouverez dans la FAQ, les sources ou les tutoriels, de l'information accessible au plus grand nombre, plein de bonnes choses à consulter sans modération![]()
Des tutoriels pour apprendre à créer des formulaires de planning dans vos applications Access :
Gestion sur un planning des présences et des absences des employés
Gestion des rendez-vous sur un calendrier mensuel
Importer un fichier JSON dans une base de données Access :
Import Fichier JSON
Hello,
Ça ressemble à la proposition de @Obsidian non ?Après il faut voir bien sûr si ça peut se gérer uniquement à ce niveau là, peut-être en définissant le type de tir à l'aide d'un attribut type_tir au moment de la création de l'objet. Et sinon les propositions qui ont été faites me semblent aussi valables.
Ah, du coup je veux bien voir la proposition par le code, car celle de @umfred et @Obsidian se recoupent...Et sinon les propositions qui ont été faites me semblent aussi valables.
D'ailleurs il y a un pattern qui est nommé pour cela, c'est le pattern stratégie
C'est une demande purement technique, mais lorsqu'on commence à toucher aux objets, en général il existe une histoire permettant de les faire communiquer ensemble, dommage de ne pas avoir plus de contexte précis sur l'histoire du jeuEn python je sais rajouter des attributs à un objet qu'il n'a pas dans sa classe, mais je sais pas faire pour les méthodes.![]()
Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)
lambda, c'est une fonction, d'ailleurs la PEP8 propose d'éviter son utilisation... on peut donc se douter de la non obligation à l'utiliser quelque soit le cas de ce keyword.Tu peux ajouter une fonction lambda en tant qu'attribut d'instance.
Après une autre solution que je ne recommanderai pas : MethodType
https://stackoverflow.com/questions/...type-in-python
Ce qu'il faut savoir c'est que les IDE n'aiment pas tout ce qui est création/modification dynamique, et à debug ça devient vite complexe...
Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)
Bonjour,
ça ressemble en effet, mais mon questionnement venait surtout du code d'origine de nouby donné dans la première discussion sur le même sujet, dans lequel la méthode tirer() possède un argument arme. ça voudrait dire que le vaisseau peut changer d'arme et donc ça peut permettre de choisir entre les propositions déjà faites.
Je proposais en fait si c'est possible d'aller au plus simple et de garder l'essentiel du code de nouby en modifiant surtout la méthode tirer() et en ajoutant un attribut à la sous-classe Vaisseau :
Cdlt,
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 import pygame as py class Vehicule: def __init__(self, nom, position, vitesse): # Uniquement ce qui est commun à tous les véhicules self.nom = nom self.position = position self.vitesse = vitesse def avancer(self): self.position[1] -= self.vitesse[1] class Vaisseau(Vehicule): def __init__(self, nom, position, vitesse, type_arme): # 1. On initialise la base du véhicule super().__init__(nom, position, vitesse) # 2. On ajoute les spécificités du Vaisseau self.type_arme = type_arme self.missiles = [] def tirer(self): if self.type_arme == "missile": #...Logique pour tirer 1 missile self.missiles.append(py.Rect(self.position[0] + 10, self.position[1], 8, 8)) elif self.type_arme == "double_boulet": #...code pour tirer 1 double_boulet
Vous trouverez dans la FAQ, les sources ou les tutoriels, de l'information accessible au plus grand nombre, plein de bonnes choses à consulter sans modération![]()
Des tutoriels pour apprendre à créer des formulaires de planning dans vos applications Access :
Gestion sur un planning des présences et des absences des employés
Gestion des rendez-vous sur un calendrier mensuel
Importer un fichier JSON dans une base de données Access :
Import Fichier JSON
Ah oui ! On en revient à ce que je disais précédemment, le contexte !dans lequel la méthode tirer() possède un argument arme. ça voudrait dire que le vaisseau peut changer d'arme et donc ça peut permettre de choisir entre les propositions déjà faites.
Ici, le PO n'indique jamais à mon sens cette possibilité, je dirais même que c'est le contraire... un vaisseau -> une arme
Mais je comprend où tu veux en venir, et ça semble être une autre histoire que celle racontée par @nouby![]()
Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)
Oui il faut plus de détails on est d'accord..
Vous trouverez dans la FAQ, les sources ou les tutoriels, de l'information accessible au plus grand nombre, plein de bonnes choses à consulter sans modération![]()
Des tutoriels pour apprendre à créer des formulaires de planning dans vos applications Access :
Gestion sur un planning des présences et des absences des employés
Gestion des rendez-vous sur un calendrier mensuel
Importer un fichier JSON dans une base de données Access :
Import Fichier JSON
@nouby
Une solution qui n'est pas dans celles proposées et où j'ai l'impression se rapproche plus de votre demande et de votre niveau actuel serait de simplement passer la fonction de tir lors de la création du vaisseau, sans créer d'usines à gaz orientées objet.
Ça ressemble plus à une stratégie orientée fonctions... Mécaniquement c'est comme un callback, mais conceptuellement, c'est l'implémentation du Pattern Stratégie via les fonctions.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 def tir_missile(): print("Tire un missile !") def tir_boulets(): print("Tire deux boulets !") class Vaisseau: def __init__(self, nom, fonction_de_tir): self.nom = nom self.action_tirer = fonction_de_tir vaisseau1 = Vaisseau("Vaisseau 1", tir_missile) vaisseau2 = Vaisseau("Vaisseau 2", tir_boulets) vaisseau2.action_tirer() # Tire deux boulets !
Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)
Vous trouverez dans la FAQ, les sources ou les tutoriels, de l'information accessible au plus grand nombre, plein de bonnes choses à consulter sans modération![]()
Des tutoriels pour apprendre à créer des formulaires de planning dans vos applications Access :
Gestion sur un planning des présences et des absences des employés
Gestion des rendez-vous sur un calendrier mensuel
Importer un fichier JSON dans une base de données Access :
Import Fichier JSON
Merci beaucoup !!!
plusieurs belles solutions ont été proposées, et je vais faire au mieux, encore merci !!!
En plus j'ai appris là des choses très interessantes.
Partager