How does `with canvas:` (Python `with something () as x:`) work implicitly in Kivy?

I just realized that there is something mysterious (at least for me) in how you can add vertex instructions to Kivy using the with Python statement. For example, the with method is used like this:

 ... some code class MyWidget(Widget) ... some code def some_method (self): with self.canvas: Rectangle(pos=self.pos, size=self.size) 

At the beginning, I thought it was just a Python statement, which I used sometimes. But suddenly I understand that this is not so. Usually it looks more (an example is taken from here ):

 with open('output.txt', 'w') as f: f.write('Hi there!') 

After the instance, there is usually as and something like the alias of the object. In the Kivy example, we do not define an alias, which is still in order. But the part that puzzles me is that the Rectangle command is still related to self.canvas. After reading the with statement, I am pretty sure that the Kivy code should be written as follows:

 class MyWidget(Widget) ... some code def some_method (self): with self.canvas as c: c.add (Rectangle(pos=self.pos, size=self.size)) 

I assume that inside the add method is the one that is being called. It is assumed that we can simply add rectangles using self.add (Rectangle(pos=self.pos, size=self.size))

Am I missing something in the with Python statement? or is it somehow implementing Qiwi?

+6
source share
2 answers

I do not know Qiwi, but I think I can guess how this particular construction work is.

Instead of holding the handle to the object you are interacting with (canvas?), The with statement is programmed to store it in some global variable that is hidden to you. Then, the operations you use inside with use this global variable to retrieve the object. At the end of the block, the global variable is cleared as part of the clearing.

The result is a compromise: the code is less explicit (usually this is the desired function in Python). However, the code is shorter, which may lead to a better understanding (assuming the reader knows how Kivy works). This is actually one way to create embedded DSLs in Python.

There are some technical features. For example, if you want to be able to embed such constructs (put one with inside the other), instead of a simple global variable, you would like to use a global variable that stores a stack of such objects. Also, if you need to deal with stream processing, you should use a local stream variable instead of a global one. But the general mechanism is the same - Kivy uses some state, which is stored in a place outside of your direct control.

+5
source

There is nothing extraordinary with the with statement, but maybe you don't know how this works?

For any object to be used in a with statement, it must implement two methods: __enter__ and __exit__ . __enter__ is called when the with block is entered, and __exit__ is called when the block is called for some reason.

What the object does in its __enter__ method, of course, depends on it. Since I don't have Kivy code, I can only guess that its canvas.__enter__ sets the global variable somewhere and that Rectangle checks the globality to see where it should be.

+4
source

Source: https://habr.com/ru/post/947917/


All Articles