usando with - cómo saber qué variables están dentro del contexto
Pregunta
En este código 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))
Aparentemente Color
y d
y Ellipse
están dentro del espacio de nombres de self.canvas
, pero ¿cómo sabe Python eso? userdata
¿No está dentro de ese mismo espacio de nombres?
Solución
Editar:Esta respuesta se volvió un poco larga, así que aquí está el resumen:
with self.canvas
define la actualidad lienzo activo para el siguiente bloque de código.- Todas las instrucciones de dibujo como
Color
oEllipse
dibujar en el lienzo activo.
Los espacios de nombres realmente no tienen nada que ver con eso, lo que importa es el contexto (ver más abajo).
El with
La declaración le permite utilizar los llamados administradores de contexto.
La sintaxis es así.
with thing [as foo]:
dónde thing
suele ser una función decorada con el contextlib.contextmanager
decorador.Lo que hace exactamente un administrador de contexto depende de cómo thing
está implementado.
Pero lo que no hace es hacer que la variable aparezca mágicamente en su alcance.Se puede obtener una referencia al contexto mediante la opción opcional as foo
cláusula, pero eso es todo. Color
y Ellipse
en su ejemplo provienen de otro lugar (¿probablemente importaciones?).
Para saber qué es exactamente el administrador de contexto en el with self.canvas
línea lo hace, deberías mirar el Documentación API o el código fuente para kivy.graphics.instructions.Canvas
.
Aquí está el extracto relevante del tutorial:
Al usar la declaración con él, todos los comandos de dibujo sucesivos que están correctamente sangrados modificarán este lienzo.La declaración con la declaración también se asegura de que después de nuestro dibujo, el estado interno se pueda limpiar correctamente.
Entonces el usar de Color
y Ellipse
afecta self.canvas
, pero no están definidos de ninguna manera por la declaración with.
Mirando el código fuente, así es como funciona:
def class CanvasBase(InstructionGroup):
def __enter__(self):
pushActiveCanvas(self)
def __exit__(self, *largs):
popActiveCanvas()
__enter__
y __exit__
definir qué sucede si se ingresa un administrador de contexto (antes de la primera línea de código sangrado después del with
declaración) y salió.
En este caso, el lienzo simplemente se empuja sobre un pila que define el lienzo actualmente activo (y sale de él si se sale del administrador de contexto).
En kivy.graphics.instructions.Instruction
, la clase base aparente para todas las instrucciones de dibujo, la padre está configurado en el lienzo actualmente activo:
self.parent = getActiveCanvas()
Otros consejos
De hecho, Color
y Ellipse
son importados de kivy.graphics
un poco más arriba en el código:
from kivy.graphics import Color, Ellipse
Para responder a su pregunta sobre los espacios de nombres, Python no necesita "saber" de qué espacio de nombres obtiene variables.Tiene reglas de espacio de nombres muy simples en comparación con lenguajes como Java, que buscan alcances de función, objeto, clase, global y paquete uno tras otro.Python tiene un espacio de nombres global (por módulo) y una pila de espacios de nombres locales (p. ej.las funciones anidadas pueden acceder a las variables desde funciones externas).Simplemente recorre la lista de ámbitos hasta que encuentra el nombre de la variable en cuestión.
El with
La afirmación anterior tiene un significado especial, pero creo que incluso with
no puede introducir implícitamente nuevas variables en el ámbito local (puede introducir una variable explícitamente con el as
cláusula, sin embargo).