Python sous-classe accès à la variable de classe parent
j'ai été surpris d'apprendre qu'une variable de classe d'une sous-classe ne peut accéder à une variable de classe du parent sans indiquer spécifiquement le nom de classe du parent:
>>> class A(object):
... x = 0
...
>>> class B(A):
... y = x+1
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in B
NameError: name 'x' is not defined
>>> class B(A):
... y = A.x + 1
...
>>> B.x
0
>>> B.y
1
Pourquoi est-ce que dans la définition de B. y je dois faire référence à A. x et pas seulement à x? Ceci est contraire à mon intuition des variables d'instance, et puisque je peux me référer à B. x après que B est défini.
2 réponses
en Python, le corps d'une classe est exécuté dans son propre espace de noms avant que la classe ne soit créée (après quoi, les membres de cet espace de noms deviennent les membres de la classe). Ainsi, lorsque l'interprète atteint y = x+1, classe B n'existe pas encore à ce point et, par conséquent, n'a pas de parent.
pour plus de détails, voir http://docs.python.org/reference/compound_stmts.html#class-definitions
les règles de détermination de la portée de Python pour les noms de domaine sont très simples et directes: l'Espace-nom local d'abord, puis (s'il y en a) les fonctions externes dans lesquelles l'Espace-nom courant est imbriqué, puis les fonctions globales, finalement intégrées. C'est tout ce qui arrive quand un nom de code est recherché, et il n'est pas nécessaire de mémoriser ou d'appliquer des règles compliquées (il n'y a pas non plus besoin d'un compilateur Python pour appliquer des règles plus compliquées).
chaque fois que vous voulez une recherche différente, vous utiliserez un qualifié nom, pas un nu nom. Les noms qualifiés sont beaucoup plus puissants parce que la recherche peut toujours être déléguée aux objets dont les attributs peuvent être demandés, et ces objets peuvent implémenter toutes les règles de recherche dont ils ont besoin. En particulier, une méthode d'instance au sein d'une classe, self.x
façon de demander le self
objet pour chercher le nom de l'attribut
corps d'une classe (par opposition au corps des méthodes définies dans une classe) s'exécute dans le cadre de l' class
déclaration avant l'objet de classe est créé ou son nom est lié (en particulier, avant que l'une quelconque des bases ait été définie comme étant des bases -- bien que ce dernier détail ne puisse jamais avoir d'importance en se référant aux noms de code, de toute façon!-).
donc, dans votre exemple, en classe B
, barename x
est regardé avec les règles universelles -- est-ce un nom lié localement? Dans la négative, est-elle liée à une fonction extérieure dans laquelle cette portée est imbriquée? Si non, est-il lié sous la forme globale ou intégrée? Si aucun de ces éléments n'est mentionné ci-dessus, l'utilisation du nom de code en question entraîne bien sûr une exception nom-erreur.
puisque vous voulez une séquence de recherche différente que les règles de recherche de nom de barenom appliquent universellement, alors clairement vous devez utiliser un nom qualifié, pas un barename; et un moment de réflexion, montrent clairement que le "choix évident" pour un nom qualifié pour votre but doit être A.x
-- puisque c'est là que vous voulez il être regardé (les bases n'ont pas été enregistrées partout encore à ce point, après tout... ce sera la métaclasse, normalement type
, qui va faire les bases-binding dans le cadre de son travail quand il est appelé après la classe le corps est fait de l'exécution de!-).
certaines personnes sont tellement attachées à d'autres règles" magiques " pour la recherche des noms de code qu'elles ne peuvent tout simplement pas supporter cet aspect de Python (inspiré à l'origine, je crois, par Modula-3, un langage peu connu qui est très bien considéré dans les cercles des théoriciens;-) -- avoir à écrire self.x
dans une méthode pour spécifier que x
doit être regardé sur self
plutôt que d'utiliser les règles de nom de code universel, par exemple, conduit de telles personnes batty.
Moi, j'aime la simplicité et l'universalité de la barename les règles de recherche, et j'aime utiliser les noms qualifiés au lieu de barenames tout temps que je veux autre forme de recherche... mais alors, ce n'est pas un secret que je suis follement amoureux de Python (j'ai mes propres ronchonnements -- par exemple, global x
comme une déclaration fait toujours ma peau rampante, où je préférerais écrire global.x
, c'est à dire, avoir global
être un nom intégré pour"le module en cours d'exécution"... Je l'amour des noms qualifiés!- ) est-il?- )