calendarcodediamondfacebookfingerglobalgoogleplushatenahomepagetopplainpocketrssservicetwitterwordpresshome2searchfoldernext-arrowback-arrowfirst-arrowlast-arrow

Python: bytes 型 と str 型の違い。変換方法

Python 3 では、文字列データを表すのに bytes と str がある。bytes のインスタンスは符号なし 8 ビット値で構成され、ASCII(文字コードの標準規格) エンコーディングで表示される。str は Unicode コードポイントの文字列を含む。

エンジニア速報は Twitter の@commteで 1 日 5 回配信しています。

Sponsored Link

bytes 型 と str 型 のポイント

  • str と bytes は同時に扱えない
  • ファイルにバイナリデータを書き込む場合、バイナリモードでオープンしなければならない
  • bytes は 8 ビットの値の列を含む
  • str は Unicode コードポイントの文字列を含む

バイナリデータについて

データ形式を大別すると、テキストとバイナリに分類される。バイナリデータとは、文字・画像・音楽・動画などテキストデータ以外のデータ。人が見ても意味が不明瞭なデータである。

バイナリデータを操作するためのものは 2 つある。

  • bytes:イミュータブル(変更不可)。バイトのタプルのようなもの
  • bytearray:ミュータブル(変更可)。バイトのリストのようなもの

組み込み型 — Python 3.10.0b2 ドキュメント

bytes 型

bytes 型はコンピューターにとって扱いやすいバイト配列を扱う。バイトの不変なシーケンス(複数の要素を順番に並べたデータ型)である。str 型は人が読み書きしやすいが、bytes 型はコンピューターにとって扱いやすい。ハードディスクに直接保存可能である。

b の後で、クォートで囲むとバイト型になる。次のコードでは、encode() を使い文字列をエンコードしている。ord()は Unicode コードポイントの数値文字を返し、chr() はそれを文字列に変換する。2 進数は bin()、hex()は 16 進数。

Unicode コードポイントを取得する場合、python3 はユニコード文字列なので、u を付けなくてよい。

# 文字列をエンコードする
print("あ".encode())
# b'\xe3\x81\x82'

a = b'\xe3\x81\x82'
print(list(a))
# [227, 129, 130]

b = [227, 129, 130]
print(bytes(b))
# b'\xe3\x81\x82'

print(bytearray(b))
# bytearray(b'\xe3\x81\x82')

# Unicode コードポイントを表す数値文字を返す
print(ord("あ"))
# 12354

# Unicode コードポイント 数値文字を文字列に変換
print(chr(12354))
# あ

# 2進数で返す
print(bin(ord("あ")))
# 0b11000001000010

# 16進数で返す
print(hex(ord("あ")))
# 0x3042

bytes リテラルでは ASCII 文字のみが許可されている。ASCII コードとは、文字を表現する 2 進数のことだが、リンク先の ASCII コード表が使われる。

参考:ASCII コード表

bytearray 型

bytearray オブジェクトはミュータブルなので変更可能である。

b = [227, 129, 130]
print(bytearray(b))
# bytearray(b'\xe3\x81\x82')

ba = bytearray(b)
ba[1] = 127
print(ba)
# bytearray(b'\xe3\x7f\x82')

str と bytes は同時に扱えない

str 型同士、bytes 型同士は連結可能だが、str 型と bytes 型を演算子(>, +, ==, %)を用いて連結することはできない。比較も不可。

a = "あ".encode()
b = "い".encode()

print(a + b)
# b'\xe3\x81\x82\xe3\x81\x84'

print("あ" + b)
# TypeError: can only concatenate str (not "bytes") to str

str は str でのみ連結可能だとエラーが表示される。

バイナリデータをファイルに書き込むとエラーになる

ファイルをテキスト書き込みモード(w)で開くとエラーになる。

with open('sample.bin', 'w') as f:
    f.write(b'\xe3\x81\x82')
# TypeError: write() argument must be str, not bytes

ファイルをバイナリ書き込みモードを使うとエラーは起きない。

with open('sample.bin', 'wb') as f:
    f.write(b'\xe3\x81\x82')

str インスタンスはバイナリエンコーディングを持たず、bytes インスタンスはテキストエンコーディングを持たない。

encode() と decode()

.encode()関数を使うと文字列をバイト型にエンコードすることができる。UTF-8 による符号化では、漢字や仮名などの表現に 3 バイトを要する。(UTF-8 - Wikipedia

c = 'あ'
print(type(c))
print(c)

# UTF-8 を指定してエンコード
e = c.encode('utf-8')
print(type(e))
# <class 'bytes'>

print(e) # バイト列を表示
# b'\xe3\x81\x82'

# エンコーディングを指定してデコード
print(e.decode('utf-8'))
# あ

次は、encode()と decode()関数を使って、文字型を確認する関数。

常に str に変換する

次のコードは常に str を返す関数。

オブジェクトの型を調べる isinstance() を用いて、第一引数に渡したオブジェクト b が第二引数に渡した bytes に属していれば、decode()の処理を行う。repr() は文字列で返す関数である。

e = 'あ'
# ひらがな「あ」をエンコードする
print(e.encode('utf-8'))
# b'\xe3\x81\x82'

def to_str(b):
    if isinstance(b, bytes):
        v = b.decode('utf-8')
    else:
        v = b
    return v

# 「あ」のエンコード文字を渡す
print(repr(to_str(b'\xe3\x81\x82')))
# 'あ'

print(repr(to_str('あ')))
# 'あ'

常に bytes に変換する

こちらは、常に bytes を返す関数。

def to_bytes(s):
    if isinstance(s, str):
        v = s.encode('utf-8')
    else:
        v = s
    return v

print(repr(to_bytes('あ')))
# b'\xe3\x81\x82'

print(repr(to_bytes(b'\xe3\x81\x82')))
# # b'\xe3\x81\x82'

参考:Effective Python 第 2 版

Python おすすめ本

スポンサード リンク

Comments

Leave a Comment

コメントする

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください