Découverte que je viens de faire à l'instant : il est possible d'écrire du code dans le corps d'une classe python, et ce code est exécuté automatiquement au chargement du module.
Exemple :
import datetime
class MyClass:
if datetime.datetime.now().isoweekday() == 5:
current_day = "trolldi"
for i in range(10):
print("TODAY IS", current_day, "!!!!!!!!")
else:
current_day = "pas trolldi"
print("current_day:", MyClass.current_day)
$ python3 bla.py
TODAY IS trolldi !!!!!!!!
TODAY IS trolldi !!!!!!!!
TODAY IS trolldi !!!!!!!!
TODAY IS trolldi !!!!!!!!
TODAY IS trolldi !!!!!!!!
TODAY IS trolldi !!!!!!!!
TODAY IS trolldi !!!!!!!!
TODAY IS trolldi !!!!!!!!
TODAY IS trolldi !!!!!!!!
TODAY IS trolldi !!!!!!!!
current_day: trolldi
Voila, c'est tout. Bisous et bon weekend à tous !
# Petite bizarrerie à noter
Posté par jeanas (site web personnel, Mastodon) . Évalué à 6 (+5/-0). Dernière modification le 11 octobre 2024 à 18:41.
J'ai toujours trouvé ça déconcertant, mais il paraît que c'est intentionnel.
[^] # Re: Petite bizarrerie à noter
Posté par Pol' uX (site web personnel) . Évalué à 6 (+4/-0).
Oui mais :
Adhérer à l'April, ça vous tente ?
[^] # Re: Petite bizarrerie à noter
Posté par David Delassus (site web personnel) . Évalué à 10 (+10/-0).
Python n'a que 2 espaces de noms : global et local.
Donc :
Quand une variable n'est pas définie dans l'espace de nom "local", Python le cherche dans l'espace de nom "global". Dans ton exemple,
x
n'existe pas dans "global", d'où l'erreur.Le corps de la classe est exécuté lors de la création de la classe, mais le corps de la méthode est exécuté que lorsqu'elle est appelée, l'espace de nom du corps de la classe n'existe donc plus à ce moment là.
Il faut imaginer que ce qu'il se passe c'est ça :
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Petite bizarrerie à noter
Posté par jeanas (site web personnel, Mastodon) . Évalué à 4 (+3/-0).
Merci, mais je comprends ce qui se passe, je suis juste déconcerté que cette décision ait été prise.
Ah non :
L'espace de nom d'une fonction est disponible dans une fonction définie à l'intérieur d'elle, c'est pour ça que je suis surpris que les classes n'aient pas le même comportement.
[^] # Re: Petite bizarrerie à noter
Posté par David Delassus (site web personnel) . Évalué à 10 (+8/-0).
Tu as bien 2 espaces de nom "global" (accessible via la fonction builtin
globals()
et "local" (accessible via la fonction builtinlocals()
.On vois ici que
x
ne fait partie ni de "global" ni de "local" :Mais alors, d'où il vient ?
Réponse courte : Du
locals()
de la fonctionf()
.Réponse longue : Pour bien comprendre ce qu'il se passe, voici le code désassemblé :
Premièrement, dans la fonction
f
on créé la variablex
avec l'opcodeMAKE_CELL
. Et on l'initialise à0
avecLOAD_CONST
etSTORE_DEREF
.Vient ensuite le
MAKE_FUNCTION
qui va créer la fonctiong()
en utilisant un "code object" (le corps de la fonctiong
compilé), ainsi qu'un tuple qui va contenir l'espace mémoire pour des variables libres.Ce tuple est créé avec l'opcode
BUILD_TUPLE 1
(tuple de 1 élément), le tuple va être créé en prenant un élément sur la pile. Cet élément c'est une référence versx
qui est chargée avecLOAD_CLOSURE
(python 3.11, depuis python 3.13 c'estLOAD_FAST
).Enfin, dans le code de la fonction
g()
, on aCOPY_FREE_VARS
qui va introduire dans la "stack frame" actuelle les variables référencées par le tuple avec lequel on a construit la "closure".Démontrant bien qu'il n'existe que 2 espaces de noms : global et local. La fonction
g
porte avec elle une copie des variables qu'elle capture. Après tout,g
n'est pas une fonction mais une "closure" (fonction + environnement).En pseudo-code python, voici à peu près ce qu'il se passe :
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Petite bizarrerie à noter
Posté par Thomas Debesse (site web personnel) . Évalué à 3 (+0/-0).
Ce n’est pas déconcertant, tu as fait une erreur :
x
n’est pas défini dans la fonction mais dans la classeC
.L’objet de classe
C
créé est passé en paramètre sous le nom deself
, et donc pour retourner le membrex
deself
il faut retournerself.x
.C’est un autre comportement qui serait déconcertant.
Le nom
self
n’est qu’une convention, tu peux faire ça si tu veux:Le fonction
meth
ne connait que l’objet créé de classeC
, quelque soit le nom donné à cet objet.C’est tout à fait normal qu’il faille accéder à cet objet de classe
C
pour accéder àx
.ce commentaire est sous licence cc by 4 et précédentes
[^] # Re: Petite bizarrerie à noter
Posté par Thomas Debesse (site web personnel) . Évalué à 3 (+0/-0).
Rien que pour s’amuser si tu veux jouer au code obfusqué tu peux faire ça :
ce commentaire est sous licence cc by 4 et précédentes
# hello
Posté par guitou . Évalué à 2 (+1/-0).
Pour le
x is not defined
, python est quand meme pas trop mal fait, il te suggere comment corriger le pbSinon, rapport a ces variables de classe, je trouve pas toujours ca tres clair, par exemple:
```
class MyClass:
my_class_var = "osef"
a = MyClass()
print(a.my_class_var)
b = MyClass()
b.my_class_var = "osef encore"
print(b.my_class_var)
print(a.my_class_var)
class MyOtherClass:
my_class_var = []
z = MyOtherClass()
z.my_class_var.append('a')
print(z.my_class_var)
y = MyOtherClass()
y.my_class_var.append('b')
print(y.my_class_var)
print(z.my_class_var)
```
$ python3 .py
osef
osef encore
osef
['a']
['a', 'b']
['a', 'b']
Avec un
string
, on pourrait croire que ca se comporte exactement comme une variable d'instance, mais avec unelist
, on constate bien que non. Ca me perturbe toujours autant!++
Gi)
[^] # Re: hello
Posté par David Delassus (site web personnel) . Évalué à 4 (+2/-0).
Lors de l'instanciation de la classe, les variables de classes sont copiées dans l'instance (self).
Les collections en Python sont des références, c'est donc la référence qui est copiée.
C'est comme en C au final :
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
# what
Posté par Christie Poutrelle (site web personnel) . Évalué à 2 (+2/-1).
Sinon je suis le seul à penser que c'est juste horrible comme comportement ?
[^] # Re: what
Posté par David Delassus (site web personnel) . Évalué à 5 (+4/-1).
Python est un langage dynamique, la création de classe est donc également dynamique. C'est un aspect de Python qui le rend très puissant, et la plupart des ORMs Python utilisent ce comportement.
Je ne vois rien de choquant ici.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: what
Posté par Christie Poutrelle (site web personnel) . Évalué à 2 (+2/-1). Dernière modification le 11 octobre 2024 à 23:17.
Dans l'absolu, c'est vrai, mais purée, les comportements imbitables que ça produit…
[^] # Re: what
Posté par David Delassus (site web personnel) . Évalué à 9 (+8/-1).
"Imbitable" ça insinue que cela serait impossible a comprendre.
Hors cela suit des règles simples et précises et d'autant plus logique si on tient compte de la nature et la philosophie du langage.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: what
Posté par Thomas Douillard . Évalué à 4 (+1/-0).
Les règles compréhensibles peuvent provoquer des comportements qui le sont moins quand on passe à l'échelle. Les règles du jeu de la vie sont simples et compréhensible. Prévoir l'évolution du système est indécidable.
[^] # Re: what
Posté par ff9097 . Évalué à 6 (+4/-0).
C'est surtout que quand tu viens du monde rigoureux (rigide ?) du typage statique c'est une chose de plus de déconcertante
[^] # Re: what
Posté par Thomas Douillard . Évalué à 4 (+1/-0).
C'est pas "que" déconcertant, c'est que ça peut faire facilement péter les hypothèses que pourra faire un code utilisant la classe, dans une bibliothèque par exemple. Tu supposes que le code va marcher partout, manque de bol lors de l'import c'est quasi une classe différente que tu utilises en important la même biblio.
En typage statique c'est aussi possible de faire ce genre de truc, avec des macros en C par exemple, mais potentiellement si t'as changé la signature d'une fonction ça passera pas la compilation. En typage dynamique tu fais péter tous les gardes fous et tu peux faire vraiment sauter toutes les hypothèses que va faire le code client, et ça peut sauter à la figure n'importe quand à l'exécution. Ça rejoint un peu le genre de critique qu'on peut faire à l'Aspect Oriented Programming, ou a la fin tout peut être modifié et tu n'as plus vraiment de garantie de savoir ce qui va être exécutés, les spécifications du code que t'utilise peuvent être changées un peu n'importe comment.
[^] # Re: what
Posté par Christophe B. (site web personnel) . Évalué à 2 (+0/-0).
Je comprends que l'on trouver certains comportements de langages déconcertants.
Chaque langage a ses forces et ses faiblesses.
Mais l'informatique n'est pas une science exacte, cela se saurait …, et surtout rien ne vaut une bonne phase de test … avec un environnement et un jeu de données probants.
[^] # Re: what
Posté par Thomas Douillard . Évalué à 4 (+1/-0).
Une vérification de certaines propriétés en phase de compilation n'est pas incompatible avec ça et permettra de concentrer les tests sur des comportements de plus haut niveau.
Par ailleurs si tu codes une librairie, par exemple, un cas d'utilisation de ce type de comportements, tu portes la responsabilité de tester ta bibliothèque sur l'utilisateur vu que tu ne connais pas nécessairement son environnement d'exécution.
# Utilité
Posté par HL . Évalué à 4 (+3/-0). Dernière modification le 13 octobre 2024 à 16:18.
Oui, Python est conçu pour permettre l'exécution en tant que script exécutable indépendamment.
Les classes sont typiquement écrites pour être importé ou exécuté en mode interactif, par exemple pour des tests unitaires. Pour cela on détecte comme suit si on est dans l'environnement d'exécution principal :
Doc officielle sur le sujet.
Envoyer un commentaire
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.