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))
显然Color
和d
以及Ellipse
位于self.canvas
的命名空间内,但Python如何知道userdata
不在同一个命名空间内?
答案 0 :(得分:5)
编辑:这个答案有点冗长,所以这里是摘要:
with self.canvas
为以下代码块定义当前活动画布。Color
或Ellipse
在活动画布上绘制。命名空间与它没有任何关系,重要的是上下文(见下文)。
with
语句允许您使用所谓的context managers。
语法就像这样
with thing [as foo]:
其中thing
通常是用contextlib.contextmanager
装饰器修饰的函数。上下文管理器究竟做了什么取决于thing
的实现方式。
但它没有做的是让变量神奇地出现在你的范围内。可以通过可选的as foo
子句获得对上下文的引用,但就是这样。您示例中的Color
和Ellipse
来自其他地方(可能是导入?)。
为了找出with self.canvas
行中的上下文管理器究竟是什么,您应该查看kivy.graphics.instructions.Canvas
的{{3}}或API documentation。
以下是教程的相关摘录:
通过对它使用with语句,所有连续的绘图命令 正确缩进的将修改此画布。 with声明 还确保在我们绘图后,可以清洁内部状态 正确的。
因此Color
和Ellipse
的使用会影响self.canvas
,但它们不会以任何方式由with语句定义。
查看源代码,这是它的工作原理:
def class CanvasBase(InstructionGroup):
def __enter__(self):
pushActiveCanvas(self)
def __exit__(self, *largs):
popActiveCanvas()
__enter__
和__exit__
定义在输入上下文管理器(在with
语句之后的第一行缩进代码之前)并退出时会发生什么。
在这种情况下,画布只会被推送到定义当前活动画布的堆栈(如果退出上下文管理器,则从其中弹出)。
在kivy.graphics.instructions.Instruction
中,所有绘图说明的明显基类,source code:
self.parent = getActiveCanvas()
答案 1 :(得分:1)
实际上,Color
和Ellipse
从kivy.graphics
导入了更高的代码:
from kivy.graphics import Color, Ellipse
要回答关于命名空间的问题,python并不需要知道"知道"它从什么名称空间获取变量。与Java等语言相比,它具有非常简单的命名空间规则,Java一个接一个地搜索函数,对象,类,全局和包范围。 Python有一个全局命名空间(每个模块)和一堆本地命名空间(例如嵌套函数可以从外部函数获取变量)。它只是在范围列表中查找,直到找到有问题的变量名称。
上面的with
语句具有特殊含义,但我认为即使with
也无法将新变量隐式地引入本地范围(它可以使用{{1}显式引入一个变量但是,条款。