In this Kivy code:
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))
Apparently Color and d and Ellipse are within the namespace of self.canvas, but how does Python know that userdata is not within that same namespace?
Edit: This answer got a bit lengthy, so here’s the summary:
with self.canvasdefines the currently active canvas for the following code block.ColororEllipsedraw on the active canvas.Namespaces don’t really have anything to do with it, it’s the context that matters (see below).
The
withstatement allows you to use so called context managers.The syntax is like this
where
thingusually is a function decorated with thecontextlib.contextmanagerdecorator. What exactly a context manager does depends on howthingis implemented.But what it doesn’t do is make variable magically appear in your scope. A reference to the context may be obtained by the optional
as fooclause, but that’s it.ColorandEllipsein your example are coming from somewhere else (probably imports?).In order to find out what exactly the context manager in the
with self.canvasline does, you should look at the API documentation or the source code forkivy.graphics.instructions.Canvas.Here’s the relevant excerpt from the tutorial:
So the use of
ColorandEllipseaffectsself.canvas, but they’re not defined in any way by the with statement.Looking at the source code, this is how it works:
__enter__and__exit__define what happens if a context manager is entered (before the first line of indented code after thewithstatement) and exited.In this case, the canvas simply gets pushed onto a stack that defines the currently active canvas (and popped from it if the context manager is exited).
In
kivy.graphics.instructions.Instruction, the apparent base class for all drawing instructions, the parent is set to the currently active canvas: