OVH Cloud OVH Cloud

classe parent

29 réponses
Avatar
JB
Bonjour a tous...

Peut etre une question de newbie mais je n'ai pas reussi à trouver de
réponse, surement que j'utilise les mauvais termes...

Voila j'ai une classe A qui a comme attribut une classe B

class A:
def __init__(self):
self.valeur="test A"
self.b=B()
class B:
def __init__(self):
self.valeur="test B"

comment faire pour récupérer A.valeur directement depuis B ?

faut il forcement, lors de l'instanciation de B, indiquer un lien vers A
? (self.B.A = self par exemple)

ou y a t il un moyen plus classe de trouver la classe 'parente' de B
directement?

voila, je suis sur que Python propose une solution pythonesque pour ca ;)

merci a tous

a+

Julien

9 réponses

1 2 3
Avatar
Bruno Desthuilliers

Bon, comme d'autres l'ont fait remarquer ta question ne distingue pas
proprement (a) classes et instances, (b) sous-classes et membres.
Comme ils ont rectifié dans le sens où ton intention porte sur les
instances, je voudrais juste te faire observer à toutes fins utiles
qu'on peut aussi écrire

class B :
valeur = 'test B'

class A :
valeur = 'test A'
b = B

et accéder de n'importe où à A.valeur, B.valeur, A.b et A.b.valeur



alors ce self.valeur dans la definition de classe ne sert à rien ?


s/definition de classe/initialiseur/

Bien que techniquement juste, le post de Boris risque AMHA d'induire pas
mal de débutants en erreur. Dans l'exemple qu'il donne, ce sont des
attributs de classe - donc partagés par toutes les instances de la
classe. Ce qui, bien que parfois utiles, n'est généralement pas ce qu'on
cherche en OO, puisque le but est que chaque instance gère son propre
état.

class A:
def __init__(self):
self.valeur="test 1"
# ca equivaut à ???
valeur="test 1"


Non, pas du tout et en aucun cas. Et ça ne correspond pas non plus a ce
qu'a posté Boris. La première ligne définit un attribut d'instance, la
seconde une variable locale.

Globalement, et en simplifiant outrageusement: en Python (comme dans pas
mal de langages objets dynamiques), un objet est une sorte de
super-dictionnaire. On peut (sauf cas particuliers) lui
ajouter/supprimer dynamiquement des attributs. Une classe est un objet
aussi, donc ça marche pareil. Accessoirement, la classe d'un objet est
un de ses attributs, et on peut changer cette classe à l'exécution (bien
que ce soit généralement une mauvaise idée...).

Bien.

Maintenant, une des différences majeures entre un objet et un simple
dictionnaire concerne les règles de résolution d'attribut (in english:
lookup). Dans le cas d'un objet, un attribut est d'abord recherché dans
les variables d'instance (stockés dans l'attribut __dict__ de
l'instance). Si cette recherche échoue, l'attribut est recherché dans la
classes (stockée dans l'attribut __class__), puis si besoin dans les
superclasses (accessibles par l'attribut __mro__ de l'objet classe). Si
l'attribut n'est toujours pas trouvé mais que la classe (ou une
superclasse) définit une fonction __getattr__, celle ci sera appelée.
Sinon, une exception AttributeError sera levée.

Petit rappel au passage: puisque tout est objet, un attribut peut
parfaitement être une fonction (instance de la classe function...).

Il existe un cas particulier: le protocole "descripteur" (explication
plus bas). Si un attribut implémente ce protocole *et* que c'est un
attribut de classe, alors ce protocole est invoqué, et c'est l'objet
retourné par cette invocation qui sera utilisé comme "valeur" de
l'attribut.

Ce protocole "descripteur" consiste en au minimum une méthode
__get__(self, obj, cls), et optionnellement une méthode __set__(self,
obj, value) et une méthode __del__(self, obj). Dans le cas courant
(attribut recherché sur l'instance), __get__ est donc appelé avec self =
l'attribut réel, obj = l'instance sur laquelle l'attribut est
recherché, et cls = la classe de obj. Si l'attribut est recherché
directement sur la classe, bien évidemment, obj est valorisé à None.

Il y a deux applications connues de ce mécanisme. La première est
évidente - que ce qui ont déjà reconnu les attributs calculés (alias
'property') - lèvent le doigt. La seconde l'est moins, alors qu'elle est
la plus utilisée : les méthodes. La classe function implémente
effectivement le protocole descripteur, de sorte que quand une fonction
est un attribut d'une classe, et que cet attribut est recherché sur une
instance, la méthode __get__ de la fonction retourne un objet method,
lequel n'est qu'un enrobage très simple autour de la fonction,
l'instance et la classe de l'instance (bin oui: les trois arguments
passés à __get__....). En (très) simplifié, voici à quoi ressemble
l'affaire:

class BoundMethod(object):
def __init__(self, func, obj, cls):
self.im_func = func
self.im_self = obj
self.im_class = cls
def __call__(self, *args, **kw):
return self.im_func(self.im_self, *args, **kw)

class UnboundMethod(object):
def __init__(self, func, cls):
self.im_func = func
self.im_class = cls
def __call__(self, obj, *args, **kw):
if not isinstance(obj, self.im_class):
raise TypeError("message bien connu ici")
return self.im_func(obj, *args, **kw)

class function(object):
# on passe toute le reste de la plomberie
def __get__(self, obj, cls):
if obj is None:
return UnboundMethod(self, cls)
else:
return BoundMethod(self, obj)


Bien bien... Maintenant, un petit tour du côté de l'instruction 'class'.
Tous les noms définis dans le corps de cette instruction - par une
instruction d'assignation (name = val) ou par une instruction 'def' -
deviennent des attributs de la classe. Mais, ce détail mis à part, ils
ne sont pas différents de ce qu'ils seraient s'ils étaient définis en
dehors du corps de la classe, puis assigné à la classe après coup. Ce
qui d'ailleurs se vérifie aisément:

class Toto(object):
... pass



...
def tutu(obj, val):
... print "dans fonction tutu : obj=%s, val=%s" % (obj, val)



...
Toto.tutu = tutu
Toto.tata = 42
Toto.tata # la classe int n'implémente pas le protocol descripteur
42



Toto.tutu # la classe fonction l'implémente, cf ci-avant
<unbound method Toto.tutu>



# on peut retrouver la fonction tutu de deux façons:
# soit dans le __dict__ de Toto:
Toto.__dict__['tutu']
<function tutu at 0x4032f304>



Toto.__dict__['tutu'] is tutu
True



# soit comme attribut im_func de l'objet method:
Toto.tutu.im_func
<function tutu at 0x4032f304>



# et on peut vérifier que les objets method sont bien
créés dynamiquement lors de l'accès à l'attribut:
m1 = Toto.tutu
m2 = Toto.tutu
m1 is m2
False



# et maintenant, le cas courant:
t = Toto()
t.tutu
<bound method Toto.tutu of <__main__.Toto object at 0x4033480c>>



t.tutu("yadda")
dans fonction tutu : obj=<__main__.Toto object at 0x4033480c>, val=yadda





C'est bien joli, tout ça, mais pour en venir à quoi me direz vous ?
Essentiellement, à expliquer pourquoi, dans une "méthode", l'utilisation
de "self" (ou quelque soit le nom utilisé) est impératif pour accéder à
l'instance. Dans la pratique:

class A(object):
val = 42

revient strictement au même que:

class AA(object):
pass
AA.val = 42

puisqu'une classe est un objet.

De même:

class B(object):
def __init__(self):
self.val = 42

b = B()

revient au même que:

class B(object):
pass

def initB(b):
b.val = 42

B.__init__ = initB

b = B()


qui revient au même que

class C(object):
pass

def initC(c):
c.val = 42

c = C()
initC(c)

qui (ouf) revient au même que

class D(object):
pass

d = D()
d.val = 42


dans ce cas je me suis bien usé les doigts pour rien ;)


Bin non. Tu a fais ce qu'il fallait.

HTH



Avatar
JB

Mmm... Et tu a combien d'instances différentes de MonServeur ? Je pose
la question parce qu'à vu de nez, j'aurais tendance à penser qu'une
classe n'est pas forcément nécessaire... Les modules Python sont
naturellement des Singletons, donc un bon moyen de partager certaines
ressources entre plusieurs objets. Les classes ne sont utiles que quand
on a besoin de plusieurs instances simultanées gérant chacune leur état
propre.


Et bien en effet, je n'aurai qu'un serveur qui tourne par machine...
donc il vaut mieux faire un module qu'une classe ?

Merci Bruno pour tous les conseils, infos , idées...

Julien

Avatar
Bruno Desthuilliers

Mmm... Et tu a combien d'instances différentes de MonServeur ? Je pose
la question parce qu'à vu de nez, j'aurais tendance à penser qu'une
classe n'est pas forcément nécessaire... Les modules Python sont
naturellement des Singletons, donc un bon moyen de partager certaines
ressources entre plusieurs objets. Les classes ne sont utiles que
quand on a besoin de plusieurs instances simultanées gérant chacune
leur état propre.


Et bien en effet, je n'aurai qu'un serveur qui tourne par machine...
donc il vaut mieux faire un module qu'une classe ?


Si ta classe est de fait conceptuellement un singleton, alors
effectivement autant faire simple[1]. Et n'oublie pas qu'un module est
un objet aussi... Tu a donc la possibilité soit de rendre ton module
MonServeur directement accessible via un import, soit de le passer en
paramètre à un initialiseur là où tu veux garder un bon découplage.

[1] Contrairement à ce qu'un certain discours tend à faire croire, OO
signifie 'orienté objet', pas 'orienté classe', et les classes ne sont
*pas* la notion centrale de la POO.

Mes deux centimes...


Avatar
Méta-MCI \(MVP\)
Bonjour !

OO signifie 'orienté objet', pas 'orienté classe'


Tu fais bien de le rappeler. Car il existe, aussi, des langages
"Orientés Objet" par prototypage, comme Javascript, qui n'utilisent pas
les classes.
Ce qui n'empêche pas certains auteurs d'utiliser ce mot, sans doute pour
mieux se faire comprendre.

@+

Michel Claveau


PS : certaines familles de langages se disent orientés objet, mais je ne
suis pas sûr ; je pense, entre autre, à la programmation orientée
aspect, à la programmation par contrats, à la programmation par
messaging. Sans compter que certains peuvent être multi-paradigmes.

Avatar
Bruno Desthuilliers
Bonjour !

OO signifie 'orienté objet', pas 'orienté classe'


Tu fais bien de le rappeler. Car il existe, aussi, des langages
"Orientés Objet" par prototypage, comme Javascript, qui n'utilisent pas
les classes.


Pour ce que ça vaut, le modèle objet de Python est plus proche de celui
de javascript que de celui de Java...


Avatar
Méta-MCI \(MVP\)
Bonsoir !

le modèle objet de Python est plus proche de celui de javascript que
de celui de Java...


Quelle audace, d'énoncer une proposition aussi engagée !
Mais, je te crois volontiers, vu que, le seul code que j'ai jamais écrit
en java comportait cinq lignes, et ne servait qu'à vérifier la
possibilité d'appeler un serveur COM (en Python).

@+

Michel Claveau

Avatar
BertrandB
Bonsoir !

le modèle objet de Python est plus proche de celui de javascript que
de celui de Java...


Quelle audace, d'énoncer une proposition aussi engagée !
Mais, je te crois volontiers, vu que, le seul code que j'ai jamais écrit
en java comportait cinq lignes, et ne servait qu'à vérifier la
possibilité d'appeler un serveur COM (en Python).

@+

Michel Claveau

Non dans le contexte du texte d'origine ce n'étais pas osé. En

javascript il est equivalent d'écrire :

object.property
object["property"]


Avatar
Bruno Desthuilliers
Bonsoir !

le modèle objet de Python est plus proche de celui de javascript que
de celui de Java...


Quelle audace, d'énoncer une proposition aussi engagée !
Mais, je te crois volontiers, vu que, le seul code que j'ai jamais
écrit en java comportait cinq lignes, et ne servait qu'à vérifier la
possibilité d'appeler un serveur COM (en Python).

@+

Michel Claveau

Non dans le contexte du texte d'origine ce n'étais pas osé. En

javascript il est equivalent d'écrire :

object.property
object["property"]


Ce n'est pas seulement à ça que je pensais (même si effectivement
Javascript et Python utilisent tous deux une table de hachage comme base
pour les objets). En Python, la "classe" d'un objet est elle-même un
objet sur lequel l'instance a une référence (modifiable à l'exécution),
et dans laquelle sont recherchés les attributs non trouvés dans
l'instance. Bref, une classe Python est techniquement très proche d'un
prototype....



Avatar
Bruno Desthuilliers
Bonsoir !

le modèle objet de Python est plus proche de celui de javascript que
de celui de Java...


Quelle audace, d'énoncer une proposition aussi engagée !


???

Je ne vois pas où est l'"audace" là-dedans. Il suffit d'étudier les
modèles objets de ces trois langages pour constater l'évidence.


1 2 3