簡體   English   中英

Python 2到3轉換:迭代子進程stdout中的行

[英]Python 2 to 3 conversion: iterating over lines in subprocess stdout

我有以下Python 2示例代碼,我想與Python 3兼容:

call = 'for i in {1..5}; do sleep 1; echo "Hello $i"; done'
p = subprocess.Popen(call, stdout=subprocess.PIPE, shell=True)
for line in iter(p.stdout.readline, ''):
    print(line, end='')

這在Python 2中運行良好,但在Python 3中, p.stdout不允許我指定編碼並且讀取它將返回字節字符串而不是Unicode,因此與''的比較將始終返回false並且iter將不會停止。 這個問題似乎暗示在Python 3.6中有一種定義這種編碼的方法。

現在,我已經將iter調用更改為當它找到一個空字節字符串iter(p.stdout.readline, b'')時停止,這似乎在2和3中工作。我的問題是:這兩個都安全嗎?和3? 有沒有更好的方法來確保兼容性?

注意:我沒有for line in p.stdout:使用for line in p.stdout:因為我需要在生成時打印每一行,根據這個答案 p.stdout有一個太大的緩沖區。

您可以添加unversal_newlines=True

p = subprocess.Popen(call, stdout=subprocess.PIPE, shell=True, universal_newlines=True)
for line in iter(p.stdout.readline, ''):
    print(line, end='')

而不是bytes ,將返回str因此''將在兩種情況下都有效。

以下是文檔對該選項的說法:

如果universal_newlines為False,則文件對象stdin,stdout和stderr將作為二進制流打開,並且不會進行行結束轉換。

如果universal_newlines為True,則這些文件對象將使用locale.getpreferredencoding(False)返回的編碼以通用換行模式打開為文本流。 對於stdin,輸入中的行結束字符'\\ n'將轉換為默認行分隔符os.linesep。 對於stdout和stderr,輸出中的所有行結尾都將轉換為'\\ n'。 有關更多信息,請參閱io.TextIOWrapper類的文檔,當其構造函數的換行參數為None時。

它沒有明確地提到bytesstr區別,但是通過聲明False返回二進制流並且True返回文本流來暗示它。

你可以使用p.communicate()然后解碼它,如果它是一個bytes對象:

from __future__ import print_function
import subprocess

def b(t):
    if isinstance(t, bytes):
        return t.decode("utf8")
    return t

call = 'for i in {1..5}; do sleep 1; echo "Hello $i"; done'
p = subprocess.Popen(call, stdout=subprocess.PIPE, shell=True)
stdout, stderr = p.communicate()

for line in iter(b(stdout).splitlines(), ''):
    print(line, end='')

這適用於Python 2和Python 3

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM