KDN*_*KDN 34 python with-statement contextmanager
我熟悉使用python的with语句作为在抛出异常时确保对象完成的一种方法.这通常看起来像
with file.open('myfile.txt') as f:
do stuff...
Run Code Online (Sandbox Code Playgroud)
这是短手的
f = file.open('myfile.txt'):
try:
do stuff...
finally:
f.close()
Run Code Online (Sandbox Code Playgroud)
或者一个班级可能出现的其他任何终结例程.
我最近遇到了一段处理OpenGL的代码:
with self.shader:
(Many OpenGL commands)
Run Code Online (Sandbox Code Playgroud)
请注意,没有任何as关键字.这是否表明,__enter__和__exit__之类的方法仍然被调用,但该对象从未明确地在块使用(即,它是通过全局或隐含引用)?还是有一些其他意义在逃避我?
Mar*_*ers 36
上下文管理器可以选择返回一个对象,将其分配给名为的标识符as.它是由__enter__方法返回的对象as,不一定是上下文管理器本身.
as <identifier>在创建新对象时使用帮助,如open()调用,但并非所有上下文管理器都是为上下文创建的.例如,它们可以重复使用并且已经创建.
进行数据库连接.您只创建一次数据库连接,但许多数据库适配器允许您将连接用作上下文管理器; 进入上下文并启动一个事务,退出它并且事务被提交(成功)或回滚(当有异常时):
with db_connection:
# do something to the database
Run Code Online (Sandbox Code Playgroud)
这里不需要创建新对象,输入db_connection.__enter__()和再次退出上下文db_connection.__exit__(),但我们已经有了对连接对象的引用.
现在,输入时可能是连接对象生成了一个游标对象.现在,将该游标对象分配为本地名称是有意义的:
with db_connection as cursor:
# use cursor to make changes to the database
Run Code Online (Sandbox Code Playgroud)
db_connection仍然没有在这里调用,它已经存在过,我们已经有了它的参考.但是无论db_connection.__enter__()生产什么现在都分配给cursor并且可以从那里使用.
这是文件对象发生的事情; open()返回一个文件对象,并fileobject.__enter__()返回文件对象本身,因此您可以open()在with语句中使用该调用,并在一个步骤中分配对新创建的对象的引用,而不是两个.没有这个小技巧,你必须使用:
f = open('myfile.txt')
with f:
# use `f` in the block
Run Code Online (Sandbox Code Playgroud)
将所有这些应用于着色器示例; 你已经有了参考self.shader.很可能self.shader.__enter__()会self.shader再次返回引用,但由于您已经拥有完全可用的引用,为什么要为此创建一个新的本地?