Popen:python 2和3之间的区别

Posted

技术标签:

【中文标题】Popen:python 2和3之间的区别【英文标题】:Popen: differences between python 2 and 3 【发布时间】:2017-11-20 10:21:16 【问题描述】:

我正在尝试将 gnuplot 的包装器从 python2 移植到 python3。大多数错误都很容易修复,但与项目的通信似乎表现出意外。我已经在以下(丑陋的)sn-p 中隔离了问题。

cmd = ['gnuplot']

p = subprocess.Popen(cmd, stdin=subprocess.PIPE,
                     stdout=subprocess.PIPE,
                     stderr=subprocess.PIPE)

p.stdin.write("set terminal dumb 80 40\n")
p.stdin.write("plot '-' w p ls 1, '-' w p ls 2, '-' w p ls 3 \n")
p.stdin.write("1 2 3\n")
p.stdin.write("2 3 4\n")
p.stdin.write("\ne\n")
p.stdin.write("e\n")
p.stdin.write("e\n")
while True:
    print(p.stdout.read(1),end="")

此代码在 python2 中有效并生成并打印结果,但在 python3 中失败。首先它抱怨字节和字符串,所以我添加universal_newlines=True。从那里我无法理解为什么它在 stdout 上不输出任何内容并在 stderr 中打印: line 4: warning: Skipping data file with no valid points line 5: warning: Skipping data file with no valid points

显然问题出在编码或通信的某个地方,因为我发出的命令是相同的,但我不知道在哪里查看或如何调试它。

欢迎提出任何建议。

【问题讨论】:

将其设为cmd = ['tee', 'logfile'],并逐字节比较两个logfile 顺便说一句,我强烈建议在输入结束时使用p.stdin.flush()p.stdin.close() 并且你应该确保对 stderr 的写入不会阻塞等待读取它们的东西,如果你要拥有stderr=subprocess.PIPE - 你很容易陷入僵局。 尝试bufsize=1 使用universal_newlines=True 启用行缓冲(默认情况下,Python 2 上为 bufsize=0,Python 3 上默认为 bufsize=-1)。 【参考方案1】:

与 Python 2 相比,Python 3 对字节和字符串进行了更严格的区分。因此,您必须将发送到标准输入的字符串编码为字节,并且必须将从标准输出接收到的字节解码为字符串。另外,当我尝试你的程序时,我必须按照 Charles 的建议添加 p.stdin.close(),这样程序就不会在 gnuplot 等待输入时挂起。

这是我想出的代码的工作版本:

import subprocess

cmd = ['gnuplot']

p = subprocess.Popen(cmd, stdin=subprocess.PIPE,
                     stdout=subprocess.PIPE,
                     stderr=subprocess.PIPE)

p.stdin.write("set terminal dumb 80 40\n".encode())
p.stdin.write("plot '-' w p ls 1, '-' w p ls 2, '-' w p ls 3\n".encode())
p.stdin.write("1 2 3\n".encode())
p.stdin.write("2 3 4\n".encode())
p.stdin.write("\ne\n".encode())
p.stdin.write("e\n".encode())
p.stdin.write("e\n".encode())
p.stdin.close()

print(p.stdout.read().decode())
print(p.stderr.read().decode())

【讨论】:

以上是关于Popen:python 2和3之间的区别的主要内容,如果未能解决你的问题,请参考以下文章

subprocess.call() 和 subprocess.Popen() 之间有啥区别使 PIPE 对前者的安全性降低?

python os.system、os.popen、subprocess.Popen的区别

Python面试高频问题: os.system()和os.popen()的区别

python 中os.system和commands.getoutput的区别

子进程 Popen 和 call 有啥区别(我该如何使用它们)?

Python Popen communicate 和wait使用上的区别