我只是意识到在使用with
Python语句在Kivy中添加顶点指令的方式中有一些神秘的东西(至少对我而言).例如,使用的方式是这样的:
... some code class MyWidget(Widget) ... some code def some_method (self): with self.canvas: Rectangle(pos=self.pos,size=self.size)
在开始时我认为这只是我偶尔使用的Python声明.但我突然意识到事实并非如此.通常它看起来更像这样(例子取自here):
with open('output.txt','w') as f: f.write('Hi there!')
实例之后通常有一个as和对象的别名.在Kivy示例中,我们没有定义和别名哪个仍然可以.但困扰我的部分是指令Rectangle仍然与self.canvas相关联.在阅读了with语句之后,我相信Kivy代码应该写成:
class MyWidget(Widget) ... some code def some_method (self): with self.canvas as c: c.add (Rectangle(pos=self.pos,size=self.size))
我假设在内部方法add是被调用的方法.假设我们可以简单地添加带有self.add的矩形(Rectangle(pos = self.pos,size = self.size))
我错过了关于Python语句的一些内容吗?或者这是Kivy实施的某种方式?
解决方法
我不知道Kivy,但我想我能猜出这个具体的建筑是如何工作的.
而不是保持与您正在交互的对象(画布?)的句柄,with语句被编程为将其存储在隐藏给您的某个全局变量中.然后,您在里面使用的语句使用该全局变量来检索对象.在块结束时,全局变量将作为清理的一部分被清除.
结果是权衡:代码不那么明确(这通常是Python中所需的特性).但是,代码更短,这可能会导致更容易理解(假设读者知道Kivy如何工作).这实际上是用Python制作嵌入式DSL的技术之一.
涉及一些技术细节.例如,如果您希望能够嵌套此类构造(将其中一个构建在另一个构造中),而不是简单的全局变量,则需要使用保留此类对象堆栈的全局变量.此外,如果您需要处理线程,则可以使用线程局部变量而不是全局变量.但是通用机制仍然是相同的 – 基维使用了一些保存在你直接控制范围之外的状态.