Voila j'ai beaucoup de mal à m'y retrouver dans les espaces de
nommage. Un objet appartient à quel espace de nommage?
Comment faire pour le mettre dans un espace de nommage donné?
Comment faire pour accéder à un objet quant on n'arrive pas à
comprendre dans quel espace de nommage il est?
Quand je lis du code j'ai la plus part du temps à voir dans
quel espace de nommage appartient tel ou tel objet. (sauf si c'est archi
basique ie que des objets global)
colLabels est un attribut de classe (C'est ça?). et je découvre que
je peux y accéder par self.colLabels (C'est un attribut de l'instance
de Foo?). Je suis perplexe. Je n'arrive même pas à expliquer ce que je
ne comprends pas.
Là pas de probleme. Je crois avoir compris. Lors de l'instanciation
__init__ crée un attribut d'instance (colLabels) qui "pointe" vers la
liste ["Forst", "Last"]
Et si je code:
class Foo(object):
... colLabels = ["Forst", "Last"]
... def GetColLabelValue(self, col):
... return colLabels[col]
...
>>> foo = Foo()
>>> foo.GetColLabelValue(1)
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 4, in GetColLabelValue
NameError: global name 'colLabels' is not defined
Là je suis encore plus perplexe. J'ai l'impression
qu'il y a quelque chose de basique que je n'ai pas
compris dans la POO. Est-ce qu'il y en a parmi vous
qui voient quel est mon probleme?
Cette action est irreversible, confirmez la suppression du commentaire ?
Signaler le commentaire
Veuillez sélectionner un problème
Nudité
Violence
Harcèlement
Fraude
Vente illégale
Discours haineux
Terrorisme
Autre
Bruno Desthuilliers
laurent FRANCOIS a écrit :
Bonjour,
Voila j'ai beaucoup de mal à m'y retrouver dans les espaces de nommage. Un objet appartient à quel espace de nommage?
Si tu poses la question en ces termes, tu risques effectivement d'avoir du mal à t'y retrouver !-)
Un objet "n'appartient" pas à un espace de nommage - ce sont les _noms_ qui appartiennent à un espace de nommage. En Python, une "variable" n'est pas une étiquette sur un espace mémoire, c'est l'association d'un nom et d'une *référence* sur un objet. Plusieurs noms, qu'ils appartiennent au même espace de nommage ou non, peuvent référencer simultanément le même objet.
En fait, le plus simple est de considérer les espaces de nommage comme des dicts nom=>référence sur un objet. Et c'est d'ailleurs souvent ce qu'ils sont effectivement.
Comment faire pour le mettre dans un espace de nommage donné?
cf ci-dessus. Tout ce que tu peux "mettre" dans un espace de nommage, c'est un nom.
Comment faire pour accéder à un objet quant on n'arrive pas à comprendre dans quel espace de nommage il est?
Là c'est autre chose.
Quand je lis du code j'ai la plus part du temps à voir dans quel espace de nommage appartient tel ou tel objet. (sauf si c'est archi basique ie que des objets global)
Oui. En fait, les classes étant elles-même des objets (instances de leur métaclasse, par défaut 'type'), c'est un attribut de l'objet "Foo". Si tu inspectes Foo.__dict__, tu y trouvera "colLabels" et "GetColLabelValue".
et je découvre que je peux y accéder par self.colLabels (C'est un attribut de l'instance de Foo?)
Non. Voir ci-dessous.
. Je suis perplexe. Je n'arrive même pas à expliquer ce que je ne comprends pas.
C'est souvent le cas quand on ne comprends pas !-)
La règle de résolution d'attributs - telle qu'implémentée par object.__getattribute__ - est la suivante:
1/ regarder si le nom existe dans le __dict__ de la classe ou d'une des classes parents. Si oui ET que l'attribut correspondant est un descripteur, retourner le résultat de l'appel à sa méthode __get__.
2/ Sinon, regarder si le nom existe dans le __dict__ (ou les __slots__) de l'instance. Si oui, retourner l'attribut correspondant.
3/ Sinon, regarder si la classe (ou une des classes parent) définit la methode __getattr__. Si oui, retourner le résultat de l'appel à __getattr__
4/ Sinon, regarder si le nom existe dans le __dict__ de la classe ou d'une des classes parents. Si oui, retourner l'attribut correspondant
5/ si toutes les méthodes précédentes ont échouées, lever un AttributeError
... >>> foo = Foo() >>> foo.GetColLabelValue(1) Traceback (most recent call last): File "<input>", line 1, in <module> File "<input>", line 4, in GetColLabelValue NameError: global name 'colLabels' is not defined
Bingo.
Là je suis encore plus perplexe. J'ai l'impression qu'il y a quelque chose de basique que je n'ai pas compris dans la POO.
Ce n'est pas un problème de POO, c'est un problème de portée et de modèle d'exécution.
En Python, à peu près tout se passe à l'exécution. Entre autres, l'instruction "class" et l'instruction "def" sont des instructions exécutables. Lors de l'exécution de "class", un espace de nommage temporaire (correspondant au bloc 'class') est créé, qui contient tous les noms définis dans ce bloc ET à ce niveau là - soit par une assignation, soit par un "def". Cet espace de nommage (un dict en fait) est ensuite passé - avec le nom de la classe et la liste des classes parentes - à la méthode __new__ de la métaclasse, laquelle méthode se charge de retourner le nouvel objet class, dûment initialisé avec les noms en question comme attributs. C'est ainsi que, dans ton example, colLabels (un objet liste) et GetColLabelValue (un objet function) deviennent des attributs de la classe Foo.
Par contre, les noms préalablement définis dans cet espace de nommage ne sont pas "capturés" par les fonctions définies dans ce même espace. Donc quand GetColLabelValue est appelée, c'est la règle normale qui s'applique pour résoudre "colLabels" - à savoir l'espace de nommage local, puis l'espace de nommage "global" (c'est à dire celui du module)[1]. Comme le nom en question n'est défini dans aucun de ses deux espaces de nommages, tu a un NameError.
Il faut bien comprendre que pour une fonction, le fait d'être définie dans un bloc "class" ne change rien en soi. Tu a exactement le même fonctionnement en définissant ta fonction en dehors de la classe et en l'assignant à la classe ensuite. Ce qui "transforme" la fonction en "méthode" (une méthode n'étant rien d'autre qu'un objet appelable avac comme attributs la fonction, la classe et l'instance) est simplement une application du protocole descripteur (et c'est d'ailleurs une des raisons d'être de ce protocole - fournir un mécanisme générique pour les attributs calculés).
Accessoirement, tout ce mode de fonctionnement est propre au modèle objet de Python, qui est très particulier.
[1] je passe sur le cas des fermetures, puisque ta fonction n'en est pas une.
HTH
laurent FRANCOIS a écrit :
Bonjour,
Voila j'ai beaucoup de mal à m'y retrouver dans les espaces de
nommage. Un objet appartient à quel espace de nommage?
Si tu poses la question en ces termes, tu risques effectivement d'avoir
du mal à t'y retrouver !-)
Un objet "n'appartient" pas à un espace de nommage - ce sont les _noms_
qui appartiennent à un espace de nommage. En Python, une "variable"
n'est pas une étiquette sur un espace mémoire, c'est l'association d'un
nom et d'une *référence* sur un objet. Plusieurs noms, qu'ils
appartiennent au même espace de nommage ou non, peuvent référencer
simultanément le même objet.
En fait, le plus simple est de considérer les espaces de nommage comme
des dicts nom=>référence sur un objet. Et c'est d'ailleurs souvent ce
qu'ils sont effectivement.
Comment faire pour le mettre dans un espace de nommage donné?
cf ci-dessus. Tout ce que tu peux "mettre" dans un espace de nommage,
c'est un nom.
Comment faire pour accéder à un objet quant on n'arrive pas à
comprendre dans quel espace de nommage il est?
Là c'est autre chose.
Quand je lis du code j'ai la plus part du temps à voir dans
quel espace de nommage appartient tel ou tel objet. (sauf si c'est archi
basique ie que des objets global)
Oui. En fait, les classes étant elles-même des objets (instances de leur
métaclasse, par défaut 'type'), c'est un attribut de l'objet "Foo". Si
tu inspectes Foo.__dict__, tu y trouvera "colLabels" et "GetColLabelValue".
et je découvre que
je peux y accéder par self.colLabels (C'est un attribut de l'instance
de Foo?)
Non. Voir ci-dessous.
. Je suis perplexe. Je n'arrive même pas à expliquer ce que je
ne comprends pas.
C'est souvent le cas quand on ne comprends pas !-)
La règle de résolution d'attributs - telle qu'implémentée par
object.__getattribute__ - est la suivante:
1/ regarder si le nom existe dans le __dict__ de la classe ou d'une des
classes parents. Si oui ET que l'attribut correspondant est un
descripteur, retourner le résultat de l'appel à sa méthode __get__.
2/ Sinon, regarder si le nom existe dans le __dict__ (ou les __slots__)
de l'instance. Si oui, retourner l'attribut correspondant.
3/ Sinon, regarder si la classe (ou une des classes parent) définit la
methode __getattr__. Si oui, retourner le résultat de l'appel à __getattr__
4/ Sinon, regarder si le nom existe dans le __dict__ de la classe ou
d'une des classes parents. Si oui, retourner l'attribut correspondant
5/ si toutes les méthodes précédentes ont échouées, lever un AttributeError
...
>>> foo = Foo()
>>> foo.GetColLabelValue(1)
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 4, in GetColLabelValue
NameError: global name 'colLabels' is not defined
Bingo.
Là je suis encore plus perplexe. J'ai l'impression
qu'il y a quelque chose de basique que je n'ai pas
compris dans la POO.
Ce n'est pas un problème de POO, c'est un problème de portée et de
modèle d'exécution.
En Python, à peu près tout se passe à l'exécution. Entre autres,
l'instruction "class" et l'instruction "def" sont des instructions
exécutables. Lors de l'exécution de "class", un espace de nommage
temporaire (correspondant au bloc 'class') est créé, qui contient tous
les noms définis dans ce bloc ET à ce niveau là - soit par une
assignation, soit par un "def". Cet espace de nommage (un dict en fait)
est ensuite passé - avec le nom de la classe et la liste des classes
parentes - à la méthode __new__ de la métaclasse, laquelle méthode se
charge de retourner le nouvel objet class, dûment initialisé avec les
noms en question comme attributs. C'est ainsi que, dans ton example,
colLabels (un objet liste) et GetColLabelValue (un objet function)
deviennent des attributs de la classe Foo.
Par contre, les noms préalablement définis dans cet espace de nommage ne
sont pas "capturés" par les fonctions définies dans ce même espace. Donc
quand GetColLabelValue est appelée, c'est la règle normale qui
s'applique pour résoudre "colLabels" - à savoir l'espace de nommage
local, puis l'espace de nommage "global" (c'est à dire celui du
module)[1]. Comme le nom en question n'est défini dans aucun de ses deux
espaces de nommages, tu a un NameError.
Il faut bien comprendre que pour une fonction, le fait d'être définie
dans un bloc "class" ne change rien en soi. Tu a exactement le même
fonctionnement en définissant ta fonction en dehors de la classe et en
l'assignant à la classe ensuite. Ce qui "transforme" la fonction en
"méthode" (une méthode n'étant rien d'autre qu'un objet appelable avac
comme attributs la fonction, la classe et l'instance) est simplement une
application du protocole descripteur (et c'est d'ailleurs une des
raisons d'être de ce protocole - fournir un mécanisme générique pour les
attributs calculés).
Accessoirement, tout ce mode de fonctionnement est propre au modèle
objet de Python, qui est très particulier.
[1] je passe sur le cas des fermetures, puisque ta fonction n'en est pas
une.
Voila j'ai beaucoup de mal à m'y retrouver dans les espaces de nommage. Un objet appartient à quel espace de nommage?
Si tu poses la question en ces termes, tu risques effectivement d'avoir du mal à t'y retrouver !-)
Un objet "n'appartient" pas à un espace de nommage - ce sont les _noms_ qui appartiennent à un espace de nommage. En Python, une "variable" n'est pas une étiquette sur un espace mémoire, c'est l'association d'un nom et d'une *référence* sur un objet. Plusieurs noms, qu'ils appartiennent au même espace de nommage ou non, peuvent référencer simultanément le même objet.
En fait, le plus simple est de considérer les espaces de nommage comme des dicts nom=>référence sur un objet. Et c'est d'ailleurs souvent ce qu'ils sont effectivement.
Comment faire pour le mettre dans un espace de nommage donné?
cf ci-dessus. Tout ce que tu peux "mettre" dans un espace de nommage, c'est un nom.
Comment faire pour accéder à un objet quant on n'arrive pas à comprendre dans quel espace de nommage il est?
Là c'est autre chose.
Quand je lis du code j'ai la plus part du temps à voir dans quel espace de nommage appartient tel ou tel objet. (sauf si c'est archi basique ie que des objets global)
Oui. En fait, les classes étant elles-même des objets (instances de leur métaclasse, par défaut 'type'), c'est un attribut de l'objet "Foo". Si tu inspectes Foo.__dict__, tu y trouvera "colLabels" et "GetColLabelValue".
et je découvre que je peux y accéder par self.colLabels (C'est un attribut de l'instance de Foo?)
Non. Voir ci-dessous.
. Je suis perplexe. Je n'arrive même pas à expliquer ce que je ne comprends pas.
C'est souvent le cas quand on ne comprends pas !-)
La règle de résolution d'attributs - telle qu'implémentée par object.__getattribute__ - est la suivante:
1/ regarder si le nom existe dans le __dict__ de la classe ou d'une des classes parents. Si oui ET que l'attribut correspondant est un descripteur, retourner le résultat de l'appel à sa méthode __get__.
2/ Sinon, regarder si le nom existe dans le __dict__ (ou les __slots__) de l'instance. Si oui, retourner l'attribut correspondant.
3/ Sinon, regarder si la classe (ou une des classes parent) définit la methode __getattr__. Si oui, retourner le résultat de l'appel à __getattr__
4/ Sinon, regarder si le nom existe dans le __dict__ de la classe ou d'une des classes parents. Si oui, retourner l'attribut correspondant
5/ si toutes les méthodes précédentes ont échouées, lever un AttributeError
... >>> foo = Foo() >>> foo.GetColLabelValue(1) Traceback (most recent call last): File "<input>", line 1, in <module> File "<input>", line 4, in GetColLabelValue NameError: global name 'colLabels' is not defined
Bingo.
Là je suis encore plus perplexe. J'ai l'impression qu'il y a quelque chose de basique que je n'ai pas compris dans la POO.
Ce n'est pas un problème de POO, c'est un problème de portée et de modèle d'exécution.
En Python, à peu près tout se passe à l'exécution. Entre autres, l'instruction "class" et l'instruction "def" sont des instructions exécutables. Lors de l'exécution de "class", un espace de nommage temporaire (correspondant au bloc 'class') est créé, qui contient tous les noms définis dans ce bloc ET à ce niveau là - soit par une assignation, soit par un "def". Cet espace de nommage (un dict en fait) est ensuite passé - avec le nom de la classe et la liste des classes parentes - à la méthode __new__ de la métaclasse, laquelle méthode se charge de retourner le nouvel objet class, dûment initialisé avec les noms en question comme attributs. C'est ainsi que, dans ton example, colLabels (un objet liste) et GetColLabelValue (un objet function) deviennent des attributs de la classe Foo.
Par contre, les noms préalablement définis dans cet espace de nommage ne sont pas "capturés" par les fonctions définies dans ce même espace. Donc quand GetColLabelValue est appelée, c'est la règle normale qui s'applique pour résoudre "colLabels" - à savoir l'espace de nommage local, puis l'espace de nommage "global" (c'est à dire celui du module)[1]. Comme le nom en question n'est défini dans aucun de ses deux espaces de nommages, tu a un NameError.
Il faut bien comprendre que pour une fonction, le fait d'être définie dans un bloc "class" ne change rien en soi. Tu a exactement le même fonctionnement en définissant ta fonction en dehors de la classe et en l'assignant à la classe ensuite. Ce qui "transforme" la fonction en "méthode" (une méthode n'étant rien d'autre qu'un objet appelable avac comme attributs la fonction, la classe et l'instance) est simplement une application du protocole descripteur (et c'est d'ailleurs une des raisons d'être de ce protocole - fournir un mécanisme générique pour les attributs calculés).
Accessoirement, tout ce mode de fonctionnement est propre au modèle objet de Python, qui est très particulier.
[1] je passe sur le cas des fermetures, puisque ta fonction n'en est pas une.