0

这个 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))

显然ColoranddEllipse在 的命名空间内self.canvas,但是 Python 怎么知道它userdata不在同一个命名空间内呢?

4

2 回答 2

5

编辑:这个答案有点冗长,所以这里是总结:

  1. with self.canvas为以下代码块定义当前活动的画布。
  2. 所有绘图指令都喜欢ColorEllipse在活动画布上绘图。

命名空间实际上与它没有任何关系,重要的是上下文(见下文)。

with语句允许您使用所谓的上下文管理器

语法是这样的

with thing [as foo]:

其中thing通常是用contextlib.contextmanager装饰器装饰的函数。上下文管理器的具体作用取决于thing实现方式。

但它没有做的是让变量神奇地出现在你的范围内。可以通过可选as foo子句获得对上下文的引用,但仅此而已。Color并且Ellipse在您的示例中来自其他地方(可能是进口?)。

为了找出该行中上下文管理器的确切作用with self.canvas您应该查看API 文档或.kivy.graphics.instructions.Canvas

以下是本教程的相关摘录:

通过使用 with 语句,所有正确缩进的连续绘图命令都将修改此画布。with 语句还确保在我们绘制之后,可以正确清理内部状态。

所以使用Colorand会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()
于 2012-10-02T15:25:16.207 回答
1

实际上,Color并且Ellipse是从kivy.graphics代码中更高的部分导入的:

from kivy.graphics import Color, Ellipse

要回答您关于命名空间的问题,python 根本不需要“知道”它从哪个命名空间获取变量。与 Java 等语言相比,它具有非常简单的命名空间规则,后者依次搜索函数、对象、类、全局和包范围。Python 有一个全局命名空间(每个模块)和一堆局部命名空间(例如,嵌套函数可以从外部函数获取变量)。它只是沿着作用域列表向下移动,直到找到有问题的变量名。

上面的with语句有特殊含义,但我认为甚至with不能将新变量隐式引入本地范围(但它可以通过as子句显式引入一个变量)。

于 2012-10-02T15:24:06.957 回答