この記事のポイント
Pythonでのバイナリデータ操作における基本的なデータ型である「bytes」について解説します。この記事を読むことで、以下のようなポイントを確認できます。
- バイナリデータを効率的に処理するための不変シーケンス型
- 画像・音声ファイルの処理やネットワーク通信で活躍する強力なツール
- 文字列との相互変換が容易で国際化アプリケーション開発に最適な機能
この記事を通して、Pythonのbytes型を用いたバイナリデータ処理 を段階的に学び、実務で応用できるスキルを身に着けていきましょう。
bytesとは?
Pythonのbytesとは、0から255までの整数値のシーケンス(配列)を表現する不変(イミュータブル)なデータ型です。バイナリデータを扱うために設計されており、テキスト処理を担当するstr型と対をなす重要な型といえます。
bytesオブジェクトは主にファイルの読み書き、ネットワーク通信、暗号化処理などのバイナリデータを扱う場面で欠かせません。Pythonでは、bytes型のデータはb'...'のように先頭にbをつけて表記します。
Unicodeテキストではなく生のバイナリデータを表すため、テキストエンコーディングの問題を気にせずにデータ処理ができるのが利点です。また、バイト単位での処理が必要なローレベルのプログラミングにおいても重要な役割を果たします。
Python 3ではテキストとバイナリデータが明確に区別されるため、両者の性質を理解して 適切に活用することがプログラムの効率化と安定性につながります。
【関連】
Pythonをもっと詳しく学ぶならpaizaラーニング
基本構文
Pythonでbytes型を扱う基本を確認しましょう。bytesオブジェクトを作成するには、いくつかの方法があります。
最もシンプルな方法は、リテラル表記を使うことです。バイト列は「b」プレフィックスを使って表現します。
# バイトリテラルの作成
SAMPLE_BYTES = b'Hello'
def show_bytes(data: bytes) -> None:
print(data)
print(type(data))
def main():
show_bytes(SAMPLE_BYTES)
if __name__ == "__main__":
main()
出力結果
b'Hello'
<class 'bytes'>
別の方法として、bytes()コンストラクタを使う方法もあります。整数のイテラブルやエンコードされた文字列からbytesオブジェクトを生成できます。
# 整数リストからのバイト列生成と文字列エンコードの例
ASCII_VALUES = [72, 101, 108, 108, 111] # "Hello"
JP_TEXT = "イヌ"
def show_bytes_from_list(values):
# 整数リストからバイト列を作成
data = bytes(values)
print(data)
def show_encoded_string(text):
# 文字列をエンコードしてバイト列に変換
encoded = text.encode('utf-8')
print(encoded)
def main():
show_bytes_from_list(ASCII_VALUES)
show_encoded_string(JP_TEXT)
if __name__ == "__main__":
main()
出力結果
b'Hello'
b'\xe3\x82\xa4\xe3\x83\x8c'
bytesオブジェクトは不変なので、一度作成すると内容を変更できません。変更可能なバイト配列が必要な場合は、bytearray型を使います。これにより、バイトデータの操作がより柔軟になります。
実用例
Pythonのbytesの実用的な使い方を具体的なコード例で見ていきましょう。bytesはファイル操作、ネットワーク通信、バイナリデータ処理など多くの場面で使われています。以下では、さまざまな実践的なシナリオでのbytes型の活用方法を紹介します。
文字列とバイト列の相互変換
文字列とバイト列の相互変換は、国際化アプリケーション開発において基本となる操作です。
# 文字列とバイト列の相互変換の例
ANIMAL_NAME = "ネコ"
def encode_text(text):
# 文字列からバイト列へ変換
data = text.encode('utf-8')
print(data)
return data
def decode_bytes(data):
# バイト列から文字列へ変換
text = data.decode('utf-8')
print(text)
def main():
animal_bytes = encode_text(ANIMAL_NAME)
decode_bytes(animal_bytes)
if __name__ == "__main__":
main()
出力結果
b'\xe3\x83\x8d\xe3\x82\xb3'
ネコ
バイナリファイルの読み書き
画像やPDFなどのバイナリファイルを扱う際にbytes型が活躍します。
# バイナリファイルへの書き込み、読み込み例
FILE_NAME = "animal.bin"
SAMPLE_BYTES = bytes([0x48, 0x61, 0x6d, 0x73, 0x74, 0x65, 0x72]) # "Hamster"
def write_bytes_to_file(filename, data):
# バイナリファイルの書き込み
with open(filename, "wb") as f:
f.write(data)
def read_bytes_from_file(filename):
# バイナリファイルの読み込み
with open(filename, "rb") as f:
content = f.read()
print(content)
return content
def main():
write_bytes_to_file(FILE_NAME, SAMPLE_BYTES)
read_bytes_from_file(FILE_NAME)
if __name__ == "__main__":
main()
出力結果
b'Hamster'
バイト配列の操作
バイト列のインデックス操作や基本メソッドの活用例です。
# バイト列のスライス、インデックスアクセスの基本メソッド
ANIMAL_DATA = b'Elephant'
def show_slice(data):
print(data[0:3])
def show_index(data):
print(data[0]) # インデックスは整数値を返す
def show_upper(data):
# bytesの基本メソッド
print(data.upper())
def main():
show_slice(ANIMAL_DATA)
show_index(ANIMAL_DATA)
show_upper(ANIMAL_DATA)
if __name__ == "__main__":
main()
出力結果
b'Ele'
69
b'ELEPHANT'
ネットワークデータの処理
ネットワークプログラミングでは、データはバイト列として送受信されます。
# ネットワーク通信のシミュレーション
RECEIVED_DATA = b'Tiger,Lion,Bear'
SEP = b','
def split_and_decode(data, sep):
animals = data.split(sep)
for animal in animals:
print(animal.decode('utf-8'))
def main():
split_and_decode(RECEIVED_DATA, SEP)
if __name__ == "__main__":
main()
出力結果
Tiger
Lion
Bear
バイト列の検索と置換
テキスト処理のような操作もバイト列で実行できます。data.find(sub) メソッドは、data 内で sub(b'Giraffe')が最初に見つかった位置のインデックスを返します。
# バイト列内の検索と置換
ZOO_DATA = b'Monkey and Giraffe'
def replace_monkey_with_gorilla(data):
print(data.replace(b'Monkey', b'Gorilla'))
print(data.find(b'Giraffe'))
def main():
replace_monkey_with_gorilla(ZOO_DATA)
if __name__ == "__main__":
main()
出力結果
b'Gorilla and Giraffe'
11
16進数表現との変換
バイト列とその16進数表現の相互変換は暗号化やハッシュ処理でよく使われます。
# 16進数文字列とバイト列の変換
import binascii
HEX_STRING = "5a6562726100" # "Zebra\0" の16進数表現
def hex_to_bytes_and_back(hex_str):
binary_data = binascii.unhexlify(hex_str)# バイト列を16進数文字列に変換
print(binary_data)
hex_back = binascii.hexlify(binary_data)
print(hex_back)
def main():
hex_to_bytes_and_back(HEX_STRING)
if __name__ == "__main__":
main()
出力結果
b'Zebra\x00'
b'5a6562726100'
データ構造のシリアライズ
構造化データをバイナリ形式でシリアライズする例です。
# Pythonオブジェクトをバイト列に変換し・復元する
import pickle
ANIMAL_DATA = {"name": "パンダ", "age": 5}
def serialize_and_deserialize(obj):
# Pythonオブジェクトをバイト列に変換
serialized = pickle.dumps(obj)
# 一部だけ表示
print(serialized[:10], "...")
# バイト列からPythonオブジェクトに復元
original = pickle.loads(serialized)
print(original)
def main():
serialize_and_deserialize(ANIMAL_DATA)
if __name__ == "__main__":
main()
出力結果
b'\x80\x04\x95 \x00\x00\x00\x00\x00\x00' ...
{'name': 'パンダ', 'age': 5}
バイト列の結合と分割
複数のバイト列を効率的に処理する方法です。
# バイト列の結合と分割の例
import pickle
PARTS = [b'Rab', b'bit']
DATA = b'Dog,Cat,Bird'
SEP = b','
def join_bytes(parts):
# バイト列の結合
whole = b''.join(parts)
print(whole)
def split_bytes(data, sep):
# バイト列の分割
animals = data.split(sep)
print(animals)
def main():
join_bytes(PARTS)
split_bytes(DATA, SEP)
if __name__ == "__main__":
main()
出力結果
b'Rabbit'
[b'Dog', b'Cat', b'Bird']
まとめ
Pythonのbytesはバイナリデータを扱うための強力なデータ型であり、さまざまな場面で活躍します。この記事では、bytesの基本から応用まで幅広く解説してきました。
bytesの活躍する場面
- ファイルの読み書き操作におけるバイナリデータの処理
- ネットワーク通信やAPIとのデータやり取り
- 画像・音声などのマルチメディアデータの操作
重要なポイント
- bytesは不変(イミュータブル)、bytearrayは可変(ミュータブル)
- 文字列(str)とバイト列(bytes)は明確に区別して扱う
- エンコード・デコードを理解してテキストとバイナリデータを適切に変換する
Pythonのbytes型を理解することで、低レイヤーのデータ操作から高度なネットワーク処理、国際化対応まで、実務に直結する幅広い応用力を獲得できます。特にPython3では文字列(Unicode)とバイナリデータ(bytes)が明確に分離されているため、違いを正しく理解し、状況に応じて使い分けることが重要です。
バイト操作は一見複雑に思えるかもしれませんが、基本を押さえれば多くの問題を効率的に解決できるツールになります。ぜひ実際のプロジェクトでPythonのbytesを活用してみてください。
レベルを更に上げたい方はpaizaプログラミングスキルチェックへ