Python 3写入管道

8

我想编写一些代码将数据放入管道中,希望解决方案能够兼容Python 2.6+和3.x。示例:

from __future__ import print_function

import subprocess
import sys

if(sys.version_info > (3,0)):
    print ("using python3")
    def raw_input(*prmpt):
        """in python3, input behaves like raw_input in python2"""
        return input(*prmpt)

class pipe(object):
    def __init__(self,openstr):
        self.gnuProcess=subprocess.Popen(openstr.split(),
                                         stdin=subprocess.PIPE)

    def putInPipe(self,mystr):
        print(mystr, file=self.gnuProcess.stdin)

if(__name__=="__main__"):
    print("This simple program just echoes what you say (control-d to exit)")
    p=pipe("cat -")
    while(True):
        try:
            inpt=raw_input()
        except EOFError:
            break
        print('putting in pipe:%s'%inpt)
        p.putInPipe(inpt)

以上代码适用于Python 2.6,但在Python 3.2中失败(请注意,以上代码大部分是使用2to3生成的 - 我只是稍微修改了一下以使其与Python 2.6兼容。)

Traceback (most recent call last):
  File "test.py", line 30, in <module>
   p.putInPipe(inpt)
  File "test.py", line 18, in putInPipe
   print(mystr, file=self.gnuProcess.stdin)
TypeError: 'str' does not support the buffer interface

我尝试了这里建议的bytes函数(例如print(bytes(mystr,'ascii')), TypeError: 'str' does not support the buffer interface, 但似乎不起作用。 有什么建议吗?


1
尝试同时兼容Python 2和3非常困难且不必要。只需编写符合惯用法、现代化(不依赖于在3.x中完全删除的内容)的代码,然后2to3应该可以工作。如果有一些地方它无法正常工作,请保留一个补丁将其更改为3.x兼容,并将其应用于2to3的输出。 - user395760
我理解2to3的目的是为了防止用户需要在同一文件中支持python2和python3。然而,我之前这样做是为了说明问题。2to3将print >> self.gnuProcess.stdin,mystr转换为print(mystr,file=self.gnuProcess.stdin)。然而,转换后的输出不起作用(引发TypeError)。我该如何编写代码,以便(至少)2to3将其转换为可用的代码? - mgilson
@delan:更好的方法是编写Python3代码,然后使用3to2工具进行翻译。 - Thomas Ahle
@ThomasAhle -- 我不确定我同意这个观点。如果你的目标是Python 3,那么你很可能会使用一些在Python2中不存在的超酷功能/模块/函数。3to2并不能真正帮助你解决这个问题... - mgilson
2个回答

9
print函数将其参数转换为字符串表示形式,并将该字符串输出到给定的文件中。该字符串表示始终是str类型,适用于Python 2.x和Python 3.x。在Python 3.x中,管道仅接受bytes或缓冲区对象,因此这种方法行不通。(即使你传递一个bytes对象给print,它也会被转换为str)。
解决方案是使用write()方法代替print(并在写入后刷新)。
self.gnuProcess.stdin.write(bytes(mystr + "\n", "ascii"))
self.gnuProcess.stdin.flush()

0

但是Python2会抱怨

bytes("something", "ascii")

如果您使用可变的bytearray,它将在Python2和Python3中不经修改地工作。

self.gnuProcess.stdin.write(bytearray(mystr + "\n", "ascii"))
self.gnuProcess.stdin.flush()

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