1. ホーム
  2. パイソン

[解決済み】Python 3 TypeError: sys.stdout.write() で bytes でなく str でなければならない。)

2022-03-03 15:39:11

質問

Pythonスクリプトから外部プロセスを実行し、実行中にそのstdoutメッセージを表示する方法を探していました。
以下のコードは動作しますが、実行時に標準出力は出力されません。終了時に以下のエラーが発生します。

sys.stdout.write(nextline) TypeError:must be str,not bytes

p = subprocess.Popen(["demo.exe"],stdout = subprocess.PIPE, stderr= subprocess.PIPE)    
# Poll process for new output until finished
while True:
    nextline = p.stdout.readline()
    if nextline == '' and p.poll() != None:
        break
    sys.stdout.write(nextline)
    sys.stdout.flush()

output = p.communicate()[0]
exitCode = p.returncode

Python 3.3.2を使っています。

解決方法は?

Python 3は文字列の扱いが少し変わっています。元々、文字列の型は の文字列があります。 str . 90 年代にユニコードが普及すると、新しい unicode タイプ は、既存のコードを壊さずに Unicode を処理するために追加されました。 1 . これは と事実上同じです。 str が、マルチバイトに対応している。

Python 3では、2種類のタイプがあります。

  • bytes 型を使用します。これは単なるバイト列であり、Pythonは以下のことを知りません。 これを文字として解釈する方法については、何もありません。
  • str 型を使用します。これもバイト列である。 が、Pythonは これらのバイトは文字として解釈されます。 .
  • を使用することで、個別の unicode 型は廃止されました。 str が unicode に対応しました。

Python 2 では、暗黙のうちにエンコーディングを仮定することは多くの問題を引き起こします。 間違ったエンコーディングを使用してしまったり、データにエンコーディングがない場合もあります。 を使用することができます(例:PNG画像)。
Pythonにどのエンコーディングを使用するかを明示的に指示する(あるいは明示的に を推測すること)は、多くの場合、より良い方法であり、"Python philosophy"に沿ったものであると言えます。 の哲学に沿ったものです。 暗黙の了解より明示の方が良い となります。

この変更は、多くの戻り値が変更されたため、Python 2と互換性がありません。 このような微妙な問題を引き起こすことがあります。 Python 3 の導入は非常に遅れています。Pythonは静的型付けを持たないので 2 のような)スクリプトで自動的に変更することは不可能です。 2to3 ).

  • を変換することができます。 str から bytesbytes('h€llo', 'utf-8') これは を生成します。 b'H\xe2\x82\xacllo' . 1文字が3文字に変換されたことに注意してください。 バイトになります。
  • を変換することができます。 bytes から strb'H\xe2\x82\xacllo'.decode('utf-8') .

もちろん、UTF-8はあなたのケースでは正しい文字セットではないかもしれません。 は正しいものを使用してください。

あなたの具体的なコードの一部で nextlinebytes でなく str , 読み stdoutstdin から subprocess は、Python 3 で次のように変更されました。 str から bytes . これは、Pythonがどのエンコーディングを使っているかを確認できないからです。これは おそらく と同じものを使用します。 sys.stdin.encoding (あなたのシステムのエンコーディング)。 が、確実ではありません。

置き換える必要があります。

sys.stdout.write(nextline)

を使っています。

sys.stdout.write(nextline.decode('utf-8'))

とか、あるいは

sys.stdout.write(nextline.decode(sys.stdout.encoding))

を変更する必要があります。 if nextline == '' から if nextline == b'' からです。

>>> '' == b''
False

また Python 3 ChangeLog , PEP 358 および PEP 3112 .


1 ASCIIでは、マルチバイト文字セットではできない巧妙なトリックがあります。最も有名な例は、"スペースによる大文字小文字の切り替え"(例. chr(ord('a') ^ ord(' ')) == 'A' やquot;6番目のビットをセットして制御文字にするquot;(例. ord('\t') + ord('@') == ord('I') ). ASCIIは、個々のビットを操作することがパフォーマンスに無視できない影響を与える操作であった時代に設計されました。

2 はい、関数アノテーションは使えますが、比較的新しい機能なので、ほとんど使われていません。