当前位置:  开发笔记 > 编程语言 > 正文

从Python中的"with"块中获取是否安全(以及为什么)?

如何解决《从Python中的"with"块中获取是否安全(以及为什么)?》经验,为你挑选了2个好方法。

协同程序和资源获取的结合似乎可能会产生一些意想不到的(或不直观的)后果.

基本问题是这样的事情是否有效:

def coroutine():
    with open(path, 'r') as fh:
        for line in fh:
            yield line

它做的.(你可以测试一下!)

更深层次的关注是with应该是替代方案finally,在此确保资源在块结束时释放.协同程序可以暂停和恢复执行with块,所以如何在冲突解决?

例如,如果在协程内部和外部打开一个带有读/写的文件,而协程尚未返回:

def coroutine():
    with open('test.txt', 'rw+') as fh:
        for line in fh:
            yield line

a = coroutine()
assert a.next() # Open the filehandle inside the coroutine first.
with open('test.txt', 'rw+') as fh: # Then open it outside.
    for line in fh:
        print 'Outside coroutine: %r' % repr(line)
assert a.next() # Can we still use it?

更新

在前面的示例中,我打算使用写入锁定文件句柄争用,但由于大多数操作系统按进程分配文件句柄,因此不存在争用.(感谢@Miles指出这个例子没有多大意义.)这是我修改过的示例,它显示了一个真正的死锁条件:

import threading

lock = threading.Lock()

def coroutine():
    with lock:
        yield 'spam'
        yield 'eggs'

generator = coroutine()
assert generator.next()
with lock: # Deadlock!
    print 'Outside the coroutine got the lock'
assert generator.next()

Miles.. 22

我真的不明白你所询问的是什么冲突,也不知道这个例子的问题:对同一个文件有两个共存的独立句柄是没问题的.

有一件事我不知道我在回答你的问题时学到了它对生成器有一个新的close()方法:

close()GeneratorExit在生成器内引发一个新异常以终止迭代.收到此异常后,生成器的代码必须提升GeneratorExitStopIteration.

close()当生成器被垃圾收集时调用,这意味着生成器的代码在生成器被销毁之前获得最后运行的机会.最后一次机会意味着try...finally现在可以保证发电机中的报表有效; 该finally条款现在总是有机会运行.这似乎是语言琐事的一小部分,但使用生成器try...finally实际上是必要的,以实现withPEP 343所描述的语句.

http://docs.python.org/whatsnew/2.5.html#pep-342-new-generator-features

因此,它处理with在生成器中使用语句的情况,但它在中间产生但从不返回 - __exit__当生成器被垃圾收集时,将调用上下文管理器的方法.


编辑:

关于文件句柄问题:我有时会忘记存在不像POSIX的平台.:)

就锁定而言,我认为RafałFowgird在说"你只需要知道发电机就像任何其他拥有资源的物体一样." 我不认为这个with语句在这里真的那么相关,因为这个函数遇到了同样的死锁问题:

def coroutine():
    lock.acquire()
    yield 'spam'
    yield 'eggs'
    lock.release()

generator = coroutine()
generator.next()
lock.acquire() # whoops!


Rafał Dowgir.. 9

我认为不存在真正的冲突.您只需要知道生成器就像保存资源的任何其他对象一样,因此创建者有责任确保它已正确完成(并避免与对象持有的资源发生冲突/死锁).我在这里看到的唯一(次要)问题是生成器没有实现上下文管理协议(至少从Python 2.5开始),所以你不能只:

with coroutine() as cr:
  doSomething(cr)

但反而必须:

cr = coroutine()
try:
  doSomething(cr)
finally:
  cr.close()

垃圾收集器close()无论如何都会这样做,但依靠它来释放资源是不好的做法.



1> Miles..:

我真的不明白你所询问的是什么冲突,也不知道这个例子的问题:对同一个文件有两个共存的独立句柄是没问题的.

有一件事我不知道我在回答你的问题时学到了它对生成器有一个新的close()方法:

close()GeneratorExit在生成器内引发一个新异常以终止迭代.收到此异常后,生成器的代码必须提升GeneratorExitStopIteration.

close()当生成器被垃圾收集时调用,这意味着生成器的代码在生成器被销毁之前获得最后运行的机会.最后一次机会意味着try...finally现在可以保证发电机中的报表有效; 该finally条款现在总是有机会运行.这似乎是语言琐事的一小部分,但使用生成器try...finally实际上是必要的,以实现withPEP 343所描述的语句.

http://docs.python.org/whatsnew/2.5.html#pep-342-new-generator-features

因此,它处理with在生成器中使用语句的情况,但它在中间产生但从不返回 - __exit__当生成器被垃圾收集时,将调用上下文管理器的方法.


编辑:

关于文件句柄问题:我有时会忘记存在不像POSIX的平台.:)

就锁定而言,我认为RafałFowgird在说"你只需要知道发电机就像任何其他拥有资源的物体一样." 我不认为这个with语句在这里真的那么相关,因为这个函数遇到了同样的死锁问题:

def coroutine():
    lock.acquire()
    yield 'spam'
    yield 'eggs'
    lock.release()

generator = coroutine()
generator.next()
lock.acquire() # whoops!



2> Rafał Dowgir..:

我认为不存在真正的冲突.您只需要知道生成器就像保存资源的任何其他对象一样,因此创建者有责任确保它已正确完成(并避免与对象持有的资源发生冲突/死锁).我在这里看到的唯一(次要)问题是生成器没有实现上下文管理协议(至少从Python 2.5开始),所以你不能只:

with coroutine() as cr:
  doSomething(cr)

但反而必须:

cr = coroutine()
try:
  doSomething(cr)
finally:
  cr.close()

垃圾收集器close()无论如何都会这样做,但依靠它来释放资源是不好的做法.


`用contextlib.closing(coroutine())作为cr:`
推荐阅读
保佑欣疼你的芯疼
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有