using with - comment savoir quelles variables se trouvent dans le contexte
Question
Dans ce code Kivy:
class MyPaintWidget(Widget):
def on_touch_down(self, touch):
userdata = touch.ud
with self.canvas:
Color(1, 1, 0)
d = 30.
Ellipse(pos=(touch.x - d/2, touch.y - d/2), size=(d, d))
userdata['line'] = Line(points=(touch.x, touch.y))
Apparemment Color
et d
et Ellipse
sont dans l'espace de noms de self.canvas
, mais comment Python sait-il cela userdata
n'est pas dans le même espace de noms ?
La solution
Modifier:Cette réponse est un peu longue, voici donc le résumé :
with self.canvas
définit l'actuel toile active pour le bloc de code suivant.- Toutes les instructions de dessin comme
Color
ouEllipse
dessiner sur le canevas actif.
Les espaces de noms n'ont pas vraiment quelque chose à voir là-dedans, c'est le contexte qui compte (voir ci-dessous).
Le with
L'instruction vous permet d'utiliser ce qu'on appelle gestionnaires de contexte.
La syntaxe est comme ça
with thing [as foo]:
où thing
est généralement une fonction décorée du contextlib.contextmanager
décorateur.Ce que fait exactement un gestionnaire de contexte dépend de la façon dont thing
est implémenté.
Mais ce qu'il ne fait pas, c'est faire apparaître comme par magie la variable dans votre champ d'application.Une référence au contexte peut être obtenue par l'option facultative as foo
clause, mais c'est tout. Color
et Ellipse
dans votre exemple, ils viennent d'ailleurs (probablement des importations ?).
Afin de savoir ce qu'est exactement le gestionnaire de contexte dans le with self.canvas
la ligne le fait, vous devriez regarder le Documentation API ou la code source pour kivy.graphics.instructions.Canvas
.
Voici l'extrait pertinent du tutoriel :
En utilisant l'instruction avec lui, toutes les commandes de dessin successives qui sont correctement en retrait modifieront cette toile.La déclaration avec assure également qu'après notre dessin, l'état interne peut être nettoyé correctement.
Alors le utiliser de Color
et Ellipse
affecte self.canvas
, mais ils ne sont en aucun cas définis par l'instruction with.
En regardant le code source, voici comment cela fonctionne :
def class CanvasBase(InstructionGroup):
def __enter__(self):
pushActiveCanvas(self)
def __exit__(self, *largs):
popActiveCanvas()
__enter__
et __exit__
définir ce qui se passe si un gestionnaire de contexte est entré (avant la première ligne de code en retrait après le with
déclaration) et quitté.
Dans ce cas, la toile est simplement poussée sur un empiler qui définit le canevas actuellement actif (et en est extrait si le gestionnaire de contexte est quitté).
Dans kivy.graphics.instructions.Instruction
, la classe de base apparente pour toutes les instructions de dessin, la le parent est défini sur le canevas actuellement actif:
self.parent = getActiveCanvas()
Autres conseils
En fait, Color
et Ellipse
sont importés de kivy.graphics
un peu plus haut dans le code :
from kivy.graphics import Color, Ellipse
Pour répondre à votre question sur les espaces de noms, python n'a pas du tout besoin de "savoir" de quel espace de noms il obtient les variables.Il a des règles d'espace de noms très simples par rapport à des langages comme Java, qui recherchent les étendues de fonction, d'objet, de classe, globales et de package les unes après les autres.Python a un espace de noms global (par module) et une pile d'espaces de noms locaux (par ex.les fonctions imbriquées peuvent accéder aux variables des fonctions externes).Il parcourt simplement la liste des étendues jusqu'à ce qu'il trouve le nom de la variable en question.
Le with
la déclaration ci-dessus a une signification particulière, mais je pense que même with
ne peut pas introduire implicitement de nouvelles variables dans la portée locale (il peut introduire explicitement une variable avec le as
clause, cependant).