我可以设置Python 3.5 subprocess.Popen管道编码吗?
我有一个边缘案例问题。我的Python脚本_A.py有以下代码(缩写) 这段代码始终在Windows8/10和Ubuntu 16.04/17.10上的Python 2.7.14和3.6.4上运行。注意,窗口上的一些kwargs值不同,但在这里它们是无关的。它在16.04版本的Python3.5.2上工作,但仅当我从Gnome终端执行script_A.py时 有时,我需要使用script_B.py来启动script_A.py而不是终端。脚本_B.py具有相同的subprocess.Popen()代码来启动相应的Python可执行文件我可以设置Python 3.5 subprocess.Popen管道编码吗?,python,python-3.x,subprocess,Python,Python 3.x,Subprocess,我有一个边缘案例问题。我的Python脚本_A.py有以下代码(缩写) 这段代码始终在Windows8/10和Ubuntu 16.04/17.10上的Python 2.7.14和3.6.4上运行。注意,窗口上的一些kwargs值不同,但在这里它们是无关的。它在16.04版本的Python3.5.2上工作,但仅当我从Gnome终端执行script_A.py时 有时,我需要使用script_B.py来启动script_A.py而不是终端。脚本_B.py具有相同的subprocess.Popen()代
script_B.py
if os.name == 'nt':
if use_py2:
executable = 'C:\\Python27\\python.exe'
else:
executable = 'C:\\Program Files\\Python36\\python.exe'
else:
if use_py2:
executable = '/usr/bin/python'
else:
executable = '/usr/bin/python3'
args = ['', 'script_A.py']
# ---- ditto above code from here ----
在Python3.5.2上使用Popen()从script_B.py执行script_A.py时,我遇到了这个错误。OS/Python版本的其他组合都不会失败
Traceback:
File "script_A.py", line 30, in run
subproc.stdin.write('%s\n' % line.rstrip())
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-4: ordinal not in range(128)
您可以在2.7.14和3.6.4中看到,我使用特定代码强制管道连接到utf-8。我不知道如何在3.5.2上设置utf-8编码
那么,有没有办法在3.5.2 Popen的管道上配置编码?将Python 3.5从支持中排除可能会更容易,但我想在这里问一下。您的输入文件是UTF-8,而您正在向其提供数据的程序需要UTF-8输入。所以直接发送原始二进制文件,而不是从字节到文本进行解码,然后从文本到字节重新编码 去掉打开
universal_newlines
模式的行和设置kwargs['encoding']
的行,并将整个替换为馈送stdin
的
块:
blinesep = os.linesep.encode('utf-8') # Since you seem to need OS specific line endings
with open('myutf-8.txt', 'rb') as fh:
for line in fh:
subproc.stdin.writelines((sline, blinesep))
textout = io.TextIOWrapper(subproc.stdout, encoding='utf-8')
如果愿意,您仍然可以将stdout
/stderr
流作为文本流处理,只需使用io.TextIOWrapper
和适当的编码显式包装它们。例如,您可以使用以下内容包装二进制stdout
:
blinesep = os.linesep.encode('utf-8') # Since you seem to need OS specific line endings
with open('myutf-8.txt', 'rb') as fh:
for line in fh:
subproc.stdin.writelines((sline, blinesep))
textout = io.TextIOWrapper(subproc.stdout, encoding='utf-8')
以下是一些旁注:
Popen
时,显式设置bufsize
是正确的,因为不这样做就不可能在Python版本之间保持一致的行为;在Python 2和Python 3.3.0及更早版本上,默认缓冲行为是无缓冲的(bufsize=0
),在3.3.1及更高版本中,默认缓冲行为是无缓冲的(-1
(意思是“使用适当的默认缓冲区大小”)。对于性能,显式使用bufsize=-1
是一个好主意;无论如何,您都在线程化读取,因此缓冲死锁不是一个问题编解码器。打开。这是一个错误(不翻译行结尾,将readline
与read(n)
调用混合在一起会产生奇怪的结果,当没有经过编码时,它甚至不会包装plainopen
的结果,因此API会发生变化,等等),速度慢,并且几乎不推荐使用。如果您需要在Python 2.6及更高版本上保持一致的行为,请使用io.open
,它在Python 2.6及更高版本上提供了Python 3内置的open
函数
暗影游侠,非常感谢你的详细建议。我将分组发表评论。(1) ,通用新行是不相关的;我不说了。推送到.stdin()的换行符是简单的“\n”(用上面的.rstrip()修复)。(2) 感谢您提供关于bufsize=-1的提示。我会试试。(3)我知道Unidode LINE_sep和codec.open()中的其他怪癖,我单独管理它们。这个特殊的临时文件是在规范化了这些怪癖之后创建的。尽管如此,我仍然需要在编解码器的所有OS和Python系统上使用相同的行为。我将查看io.open()是否可以获得相同的一致性。我对您的encode()修复程序表示怀疑,但我还是尝试了。除了它不起作用之外(如下),我还需要使用Unicode(Py3 str)格式的行。此简化版本删除了许多规范化/过滤Unicode字符串的函数(因此需要Unicode_文字)。请注意,有问题的行
suboc.stdin.write(“%s\n”%sline.rstrip())
将Unicode str发送到子进程。错误消息报告Popen()在内部应用了'ascii'编解码器
,并使用非ascii字符失败。读取原始UTF-8行并将其发送到stdin.write()会引发完全相同的错误。这恰好是阿拉伯文文本,但很可能是任何有效的UTF-8 Unicode。在Python 3.6上,kwargs['encoding']
配置是绝对关键的,因为它将Popen()配置为使用“ascii”编解码器替换为“UTF-8”编解码器。如果可能的话,我需要在3.5上使用相同的功能,但是在3.6中添加了“encoding”关键字。