with 关键字在打开文件时有效,但在调用函数时无效

Posted

技术标签:

【中文标题】with 关键字在打开文件时有效,但在调用函数时无效【英文标题】:with keyword works when openning file but not when calling a function 【发布时间】:2015-11-25 21:49:52 【问题描述】:

我正在试验多处理模块并从this 页面复制示例代码。这是一个例子:

#!/usr/bin/python
from multiprocessing import Pool
from time import sleep

def f(x):
    return x*x

if __name__ == '__main__':
    # start 4 worker processes
    with Pool(processes=4) as pool:

        # print "[0, 1, 4,..., 81]"
        print(pool.map(f, range(10)))

        # print same numbers in arbitrary order
        for i in pool.imap_unordered(f, range(10)):
            print(i)

        # evaluate "f(10)" asynchronously
        res = pool.apply_async(f, [10])
        print(res.get(timeout=1))             # prints "100"

        # make worker sleep for 10 secs
        res = pool.apply_async(sleep, [10])
        print(res.get(timeout=1))             # raises multiprocessing.TimeoutError

    # exiting the 'with'-block has stopped the pool

运行此代码后,我得到:

Traceback (most recent call last):
  File "example01.py", line 11, in <module>
    with Pool(processes=4) as pool:
AttributeError: __exit__

不知何故,我发现这是由于 with 关键字。然而,这段代码也在使用with 并且它正在运行:

#!/usr/bin/python
with open("input.csv", "wb") as filePath:
    pass
filePath.close()

当我想运行提到的示例时,我必须按照以下方式对其进行修改:

#!/usr/bin/python

from multiprocessing import Pool
from time import sleep
import traceback

def f(x):
    return x*x

if __name__ == '__main__':
  # start 4 worker processes
  # with Pool(processes=4) as pool:
  try:
    pool = Pool(processes = 4)

    # print "[0, 1, 4,..., 81]"
    print(pool.map(f, range(10)))

    # print same numbers in arbitrary order
    for i in pool.imap_unordered(f, range(10)):
      print(i)

    # evaluate "f(10)" asynchronously
    res = pool.apply_async(f, [10])
    print(res.get(timeout=1))             # prints "100"

    # make worker sleep for 10 secs
    res = pool.apply_async(sleep, [10])
    print(res.get(timeout=1))             # raises multiprocessing.TimeoutError

    # exiting the 'with'-block has stopped the pool

  # http://***.com/questions/4990718/python-about-catching-any-exception
  # http://***.com/questions/1483429/how-to-print-an-error-in-python
  # http://***.com/questions/1369526/what-is-the-python-keyword-with-used-for
  except Exception as e:
    print "Exception happened:"
    print type(e)
    print str(e)
    print traceback.print_exc()

然后输出如下所示:

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
0
1
4
9
16
25
36
49
64
81
100
Exception happened:
<class 'multiprocessing.TimeoutError'>

Traceback (most recent call last):
  File "example01_mod.py", line 29, in <module>
    print(res.get(timeout=1))             # raises multiprocessing.TimeoutError
  File "/usr/lib/python2.7/multiprocessing/pool.py", line 563, in get
    raise TimeoutError
TimeoutError
None

为什么我在使用 with 关键字时会出错,这些代码(带有和 try-catch)是等效的吗?我正在使用 python 2.7.10。

【问题讨论】:

您不能只将with 用于任何对象。对象必须是context manager。 【参考方案1】:

This PEP 描述了使用“with”关键字所需的上下文管理器接口。 Python 2.7 的 Pool 类版本不支持此接口,因此您不能按照您描述的方式使用“with”关键字。

您可以像the example here 那样直接重写代码以不使用并加入/终止池,或者您可以升级到支持池的“with”的 Python 3。

【讨论】:

您能否解释一下“上下文管理器”的含义以及“重写代码以不使用并直接加入池”的含义?并且是否可以简要解释为什么它在 python3 中工作,我的意思是它是 Pool 的问题,或者它是 python3 的特性还是什么?谢谢 为什么这在 python3 中工作可能由@Abhijit 解释“池已从 Python 3.4.3 转换为上下文管理器对象,如果您的版本早于该版本,则不能将其与上下文管理器一起使用。”如果我错了,请纠正我,PS:我不是英语母语。【参考方案2】:

您错误地假设multiprocessor Pool class of Python 2.7 返回context manager。相反,它返回worker processes 的列表。 Pool 已从 Python 3.4.3 转换为上下文管理器对象,如果您的版本早于该版本,则不能将其与上下文管理器一起使用。

要与 with 语句一起使用,表达式应该返回一个带有 enterexit 方法的对象,以便您得到熟悉的错误。

AttributeError: __exit_

【讨论】:

您能简单解释一下什么是上下文管理器吗?从您的问题来看,with 关键字似乎使用了某种数据类型。谢谢 @WakanTanka:我已经更新了链接到文档相关部分的答案,解释了什么是上下文管理器。

以上是关于with 关键字在打开文件时有效,但在调用函数时无效的主要内容,如果未能解决你的问题,请参考以下文章

电子邮件附件的存储名称 - 第一次运行时出错,但在第二次运行时有效

此 SQL 代码在 SMMS 中执行时有效,但在 .Net 中通过 ExecuteNonQuery() 调用时无效,为啥?

NSFileManager 在 Xcode 中作为发行版构建时有效,但在作为独立 OS X Cocoa 应用程序运行时无效

HTML5 视频未在 chrome 中加载,但在打开开发人员控制台时有效

AsyncTask(update) 仅在应用程序第一次打开时有效,但在 5 秒后不更新

装饰器仅在装饰方法时有效,但在使用作为参数传递的方法调用装饰器时无效