题
在 这个基维代码:
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
不在同一个命名空间内?
解决方案
编辑:这个答案有点长,所以总结如下:
with self.canvas
定义当前 活动画布 对于以下代码块。- 所有绘图说明如
Color
或者Ellipse
在活动画布上绘制。
命名空间实际上与它没有任何关系,重要的是上下文(见下文)。
这 with
声明允许您使用所谓的 上下文管理器.
语法是这样的
with thing [as foo]:
在哪里 thing
通常是一个用 contextlib.contextmanager
装饰师。上下文管理器到底做什么取决于如何 thing
已实施。
但它并没有让变量神奇地出现在你的作用域中。对上下文的引用可以通过可选的 as foo
条款,但仅此而已。 Color
和 Ellipse
在你的例子中来自其他地方(可能是进口?)。
为了找出上下文管理器到底是什么 with self.canvas
线确实如此,你应该看看 API文档 或者 源代码 为了 kivy.graphics.instructions.Canvas
.
以下是本教程的相关摘录:
通过使用Want 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
, ,所有绘图指令的明显基类, 父级设置为当前活动的画布:
self.parent = getActiveCanvas()
其他提示
实际上, Color
和 Ellipse
是从进口的 kivy.graphics
代码稍高一点:
from kivy.graphics import Color, Ellipse
要回答有关命名空间的问题,Python 根本不需要“知道”它从哪个命名空间获取变量。与 Java 等语言相比,它的命名空间规则非常简单,Java 会依次搜索函数、对象、类、全局和包范围。Python 有一个全局命名空间(每个模块)和一堆本地命名空间(例如嵌套函数可以从外部函数获取变量)。它只是沿着范围列表向下查找,直到找到有问题的变量名称。
这 with
上面的说法有特殊含义,但我认为即使 with
不能隐式地将新变量引入局部作用域(它可以使用 as
不过,条款)。