Python 2.7 / exec / 出了什么问题?

5

我有一段代码,它在Python 2.5中可以正常运行,但在2.7中不能:

import sys
import traceback
try:
    from io import StringIO
except:
    from StringIO import StringIO

def CaptureExec(stmt):
    oldio = (sys.stdin, sys.stdout, sys.stderr)
    sio = StringIO()
    sys.stdout = sys.stderr = sio
    try:
        exec(stmt, globals(), globals())
        out = sio.getvalue()
    except Exception, e:
        out = str(e) + "\n" + traceback.format_exc()
    sys.stdin, sys.stdout, sys.stderr = oldio
    return out

print "%s" % CaptureExec("""
import random
print "hello world"
""")

我得到了以下错误信息:

期望传入字符串类型的参数,但实际接收到的是 'str'
Traceback (most recent call last):
  File "D:\3.py", line 13, in CaptureExec
    exec(stmt, globals(), globals())
  File "", line 3, in 
TypeError: 期望传入字符串类型的参数,但实际接收到的是 'str'

2
小注释:Pythonic 风格是仅在类中使用 TitleCase,应该是 captureExeccapture_exec。此外,在 try...except 块中应该特别捕获 ImportError - Katriel
2个回答

15

io.StringIO 在 Python 2.7 中很容易引起困惑,因为它是从 3.x 版本的字节/字符串世界中回溯而来的。这段代码会得到与你相同的错误:

from io import StringIO
sio = StringIO()
sio.write("Hello\n")

原因:

Traceback (most recent call last):
  File "so2.py", line 3, in <module>
    sio.write("Hello\n")
TypeError: string argument expected, got 'str'

如果你只使用Python 2.x版本,则跳过io模块,继续使用StringIO。 如果你真的想使用io,请将导入方式更改为:
from io import BytesIO as StringIO

+1 for BytesIO。我认为很多旧的2.x代码将不太兼容2.7 :/ 看起来2.7将更像是迈向3.x的垫脚石 - John La Rooy

2

这是个不好的消息

io.StringIO 希望使用 Unicode 进行操作。你可能认为可以通过在要打印的字符串前面加上 u 来解决它,像这样:

print "%s" % CaptureExec("""
import random
print u"hello world"
""")

然而对于这个问题,print 并不是最好的解决方案,因为它会导致在 StringIO 中进行两次写操作。第一次写入的是 u"hello world",这没问题,但是接下来就写入了 "\n"

因此,你需要写类似下面这样的代码:

print "%s" % CaptureExec("""
import random
sys.stdout.write(u"hello world\n")
""")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接