`with canvas:` (Python `with something() as x:`) 如何在 Kivy 中隐式工作?
问题描述
我刚刚意识到在 Kivy 中使用 with
Python 语句添加顶点指令的方式有些神秘(至少对我而言).例如,with
的使用方式是这样的:
I just realized there is something mysterious (at least for me) in the way you can add vertex instructions in Kivy with the with
Python statement. For example, the way with
is used goes something like this:
... some code
class MyWidget(Widget)
... some code
def some_method (self):
with self.canvas:
Rectangle(pos=self.pos, size=self.size)
一开始我以为只是我偶尔使用的with
Python语句.但突然间我意识到事实并非如此.通常它看起来更像这样(示例取自 这里):
At the beginning I thought that it was just the with
Python statement that I have used occasionally. But suddenly I realize it is not. Usually it looks more like this (example taken from here):
with open('output.txt', 'w') as f:
f.write('Hi there!')
在实例之后通常有一个 as
以及对象的类似和别名.在 Kivy 示例中,我们没有定义和别名,这仍然可以.但令我困惑的部分是指令 Rectangle 仍然与 self.canvas 相关联.在阅读了 with
语句之后,我非常确信 Kivy 代码应该写成这样:
There is usually an as
after the instance and something like and alias to the object. In the Kivy example we don't define and alias which is still ok. But the part that puzzles me is that instruction Rectangle is still associated to the self.canvas. After reading about the with
statement, I am quite convinced that the Kivy code should be written like:
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))
I am assuming that internally the method add
is the one being called. The assumption is based that we can simply add the rectangles with self.add (Rectangle(pos=self.pos, size=self.size))
我是否遗漏了关于 with
Python 语句的某些内容?或者这是 Kivy 实现的某种东西?
Am I missing something about the with
Python statement? or is this somehow something Kivy implements?
解决方案
我不知道 Kivy,但我想我可以猜到这个具体的构造是如何工作的.
I don't know Kivy, but I think I can guess how this specific construction work.
with
语句不是保留与您正在交互的对象(画布?)的句柄,而是将其存储在对您隐藏的某个全局变量中.然后,您在 with
中使用的语句使用该全局变量来检索对象.在块的末尾,全局变量作为清理的一部分被清除.
Instead of keeping a handle to the object you are interacting with (the canvas?), the with
statement is programmed to store it in some global variable, hidden to you. Then, the statements you use inside with
use that global variable to retrieve the object. At the end of the block, the global variable is cleared as part of cleanup.
结果是一种权衡:代码不那么明确(这通常是 Python 中需要的特性).但是,代码更短,这可能更容易理解(假设读者知道 Kivy 的工作原理).这实际上是在 Python 中制作嵌入式 DSL 的技术之一.
The result is a trade-off: code is less explicit (which is usually a desired feature in Python). However, the code is shorter, which might lead to easier understanding (with the assumption that the reader knows how Kivy works). This is actually one of the techniques of making embedded DSLs in Python.
涉及一些技术细节.例如,如果您希望能够嵌套这样的结构(将一个 with
放在另一个中),而不是一个简单的全局变量,您可能希望使用一个全局变量来保存这些对象的堆栈.此外,如果您需要处理线程,您将使用线程局部变量而不是全局变量.但是通用机制仍然是相同的——Kivy 使用了一些保存在你无法直接控制的地方的状态.
There are some technicalities involved. For example, if you want to be able to nest such constructions (put one with
inside another), instead of a simple global variable you would want to use a global variable that keeps a stack of such objects. Also, if you need to deal with threading, you would use a thread-local variable instead of a global one. But the generic mechanism is still the same—Kivy uses some state which is kept in a place outside your direct control.
相关文章