Popen: Python 2和3之间的区别

7

我正在尝试将一个gnuplot的Python2封装器移植到Python3。大多数错误都很容易修复,但是与该项目的通信似乎表现出意外的行为。我已经在以下(丑陋的)代码片段中隔离了问题。

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 - Charles Duffy
顺便说一下,我强烈建议在输入结束时使用 p.stdin.flush()p.stdin.close() - Charles Duffy
而且你必须确保写入stderr时不会阻塞等待读取它们的内容,如果你使用stderr=subprocess.PIPE,那么很容易陷入死锁。 - Charles Duffy
1
尝试使用bufsize=1universal_newlines=True启用行缓冲(在Python 2中为bufsize=0,在Python 3中默认为bufsize=-1)。 - jfs
1个回答

8

Python 3 在字节和字符串方面与 Python 2 有更强的区别。因此,您必须将要发送到标准输入的字符串编码为字节,并且必须将从标准输出接收到的字节解码为字符串。另外,当我测试您的程序时,我需要像 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())

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