Documentation Python

Pythonで文字列(str)をバイト列(bytes)に変換する方法について解説します。ファイルの読み書きやネットワーク通信では、この変換が頻繁に必要になります。

変換方法の比較

方法構文推奨度用途
encode()s.encode('utf-8')⭐⭐⭐一般的な文字列変換
bytes()bytes(s, 'utf-8')⭐⭐コンストラクタ形式
リテラルb'hello'⭐⭐⭐ASCII文字列のみ

encode() メソッド(推奨)

str.encode()は文字列をバイト列に変換する最も一般的な方法です。

# 基本的な使い方
text = "Hello, World!"
bytes_data = text.encode('utf-8')

print(bytes_data)        # b'Hello, World!'
print(type(bytes_data))  # <class 'bytes'>

# デフォルトはUTF-8
bytes_data = text.encode()  # encoding='utf-8'と同じ

# 日本語の場合
japanese = "こんにちは"
bytes_jp = japanese.encode('utf-8')
print(bytes_jp)  # b'\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xe3\x81\xaf'
print(len(bytes_jp))  # 15バイト(日本語1文字 = 3バイト)

エンコーディングの種類

text = "こんにちは"

# UTF-8(推奨)
utf8 = text.encode('utf-8')
print(f"UTF-8: {len(utf8)} bytes")  # 15 bytes

# UTF-16
utf16 = text.encode('utf-16')
print(f"UTF-16: {len(utf16)} bytes")  # 12 bytes (BOM含む)

# Shift_JIS(レガシー)
sjis = text.encode('shift_jis')
print(f"Shift_JIS: {len(sjis)} bytes")  # 10 bytes

# EUC-JP(レガシー)
eucjp = text.encode('euc-jp')
print(f"EUC-JP: {len(eucjp)} bytes")  # 10 bytes

エラーハンドリング

# エンコードできない文字がある場合の処理
text = "Hello 🌍 World"

# strict(デフォルト): エラーを発生
try:
    result = text.encode('ascii', errors='strict')
except UnicodeEncodeError as e:
    print(f"Error: {e}")

# ignore: エンコードできない文字を無視
result = text.encode('ascii', errors='ignore')
print(result)  # b'Hello  World'

# replace: ?で置換
result = text.encode('ascii', errors='replace')
print(result)  # b'Hello ? World'

# xmlcharrefreplace: XML文字参照で置換
result = text.encode('ascii', errors='xmlcharrefreplace')
print(result)  # b'Hello &#127757; World'

# backslashreplace: バックスラッシュエスケープで置換
result = text.encode('ascii', errors='backslashreplace')
print(result)  # b'Hello \\U0001f30d World'

bytes() コンストラクタ

bytes()はより汎用的なコンストラクタで、複数の方法でバイト列を作成できます。

# 文字列からバイト列を作成
text = "Hello"
bytes_data = bytes(text, 'utf-8')
print(bytes_data)  # b'Hello'

# 整数のリストから作成
bytes_from_list = bytes([72, 101, 108, 108, 111])
print(bytes_from_list)  # b'Hello'

# 指定サイズのゼロ埋めバイト列
zero_bytes = bytes(10)
print(zero_bytes)  # b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

# 空のバイト列
empty = bytes()
print(empty)  # b''

バイト列から文字列への変換(decode)

# バイト列から文字列に戻す
bytes_data = b'\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xe3\x81\xaf'
text = bytes_data.decode('utf-8')
print(text)  # こんにちは

# エラーハンドリング
invalid_bytes = b'\xff\xfe'
try:
    text = invalid_bytes.decode('utf-8')
except UnicodeDecodeError as e:
    print(f"Decode error: {e}")

# エラーを無視
text = invalid_bytes.decode('utf-8', errors='ignore')
print(text)  # (空文字列)

# エラーを置換
text = invalid_bytes.decode('utf-8', errors='replace')
print(text)  # ��

実践的な使用例

ファイルの読み書き

# バイナリモードでファイルに書き込み
text = "日本語のテキスト"
with open('output.bin', 'wb') as f:
    f.write(text.encode('utf-8'))

# バイナリモードでファイルを読み込み
with open('output.bin', 'rb') as f:
    bytes_data = f.read()
    text = bytes_data.decode('utf-8')
    print(text)  # 日本語のテキスト

HTTPリクエスト/レスポンス

import urllib.request

# URLからデータを取得(bytes)
url = "https://example.com"
with urllib.request.urlopen(url) as response:
    bytes_data = response.read()
    # 文字列に変換
    html = bytes_data.decode('utf-8')
    print(html[:100])

Base64エンコーディング

import base64

# 文字列をBase64でエンコード
text = "Hello, World!"
bytes_data = text.encode('utf-8')
base64_bytes = base64.b64encode(bytes_data)
base64_str = base64_bytes.decode('ascii')
print(base64_str)  # SGVsbG8sIFdvcmxkIQ==

# Base64からデコード
decoded_bytes = base64.b64decode(base64_str)
original_text = decoded_bytes.decode('utf-8')
print(original_text)  # Hello, World!

ハッシュ計算

import hashlib

text = "パスワード"

# SHA-256ハッシュを計算
bytes_data = text.encode('utf-8')
hash_object = hashlib.sha256(bytes_data)
hash_hex = hash_object.hexdigest()
print(hash_hex)

ソケット通信

import socket

def send_message(host: str, port: int, message: str):
    """メッセージを送信"""
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.connect((host, port))
        # 文字列をバイト列に変換して送信
        s.sendall(message.encode('utf-8'))

        # レスポンスを受信してデコード
        response = s.recv(1024)
        return response.decode('utf-8')

strとbytesの違い

# str: Unicode文字列
s = "Hello"
print(type(s))     # <class 'str'>
print(len(s))      # 5(文字数)
print(s[0])        # 'H'(文字)

# bytes: バイト列
b = b"Hello"
print(type(b))     # <class 'bytes'>
print(len(b))      # 5(バイト数)
print(b[0])        # 72(ASCIIコード)

# 日本語の場合
s = "あ"
b = s.encode('utf-8')
print(len(s))      # 1(1文字)
print(len(b))      # 3(3バイト)

bytearrayとの違い

# bytes: イミュータブル(変更不可)
b = b"Hello"
# b[0] = 74  # TypeError: 'bytes' object does not support item assignment

# bytearray: ミュータブル(変更可能)
ba = bytearray(b"Hello")
ba[0] = 74  # 'J'のASCIIコード
print(ba)   # bytearray(b'Jello')

# 変換
text = "Hello"
ba = bytearray(text, 'utf-8')
ba.extend(b" World")
result = ba.decode('utf-8')
print(result)  # Hello World

よくあるエラーと対処法

# TypeError: a bytes-like object is required, not 'str'
# 原因: バイナリモードのファイルに文字列を書き込もうとした
with open('file.bin', 'wb') as f:
    # f.write("Hello")  # TypeError
    f.write("Hello".encode('utf-8'))  # 正しい

# UnicodeDecodeError
# 原因: 間違ったエンコーディングでデコード
bytes_data = "こんにちは".encode('shift_jis')
try:
    text = bytes_data.decode('utf-8')  # Error
except UnicodeDecodeError:
    text = bytes_data.decode('shift_jis')  # 正しい

# UnicodeEncodeError
# 原因: エンコーディングがサポートしていない文字
text = "絵文字: 🎉"
try:
    bytes_data = text.encode('ascii')  # Error
except UnicodeEncodeError:
    bytes_data = text.encode('utf-8')  # 正しい

まとめ

操作推奨方法
文字列 → バイト列s.encode('utf-8')
バイト列 → 文字列b.decode('utf-8')
バイトリテラルb'ascii only'
可変バイト列bytearray(s, 'utf-8')

encode()メソッドを使うのが最も直感的で、対となるdecode()メソッドと組み合わせて使用できるため推奨されます。エンコーディングは明示的に指定し、必要に応じてエラーハンドリングを設定しましょう。

参考文献

円