Python dataclass を文字列リテラルの辞書に変換する方法
Python の dataclass を辞書に変換する際、特定のフィールド(特に UUID など)を文字列リテラルとして表現したい場合があります。この記事では、効率的で適切な方法をいくつか紹介します。
問題点
以下のような dataclass がある場合:
from dataclasses import dataclass
import uuid
@dataclass
class MessageHeader:
message_id: uuid.UUID
単純に辞書化すると、message_id
フィールドは UUID オブジェクトのままになります:
header = MessageHeader(message_id=uuid.uuid4())
print(header.__dict__)
# {'message_id': UUID('383b0bfc-743e-4738-8361-27e6a0753b5a')}
しかし、以下のように文字列リテラルとして表現したい場合があります:
{'message_id': '383b0bfc-743e-4738-8361-27e6a0753b5a'}
解決方法
方法 1: シンプルな辞書内包表記
最もシンプルで読みやすい方法です:
from dataclasses import dataclass, asdict
import uuid
@dataclass
class MessageHeader:
message_id: uuid.UUID
def to_dict(self):
return {k: str(v) for k, v in asdict(self).items()}
使用例:
header = MessageHeader(message_id=uuid.uuid4())
result = header.to_dict()
print(result)
# {'message_id': '383b0bfc-743e-4738-8361-27e6a0753b5a'}
TIP
asdict()
はネストした dataclass や複合データ構造も正しく処理しますが、パフォーマンスが若干低下する可能性があります。
方法 2: __dict__
を直接使用(高速)
パフォーマンスが重要な場合:
@dataclass
class MessageHeader:
message_id: uuid.UUID
def to_dict(self):
result = self.__dict__.copy()
result['message_id'] = str(result['message_id'])
return result
WARNING
この方法は __slots__
を使用しているクラスでは動作しないことに注意してください。
方法 3: 条件付き変換
複数のフィールドを条件付きで変換する場合:
@dataclass
class MessageHeader:
message_id: uuid.UUID
count: int
def to_dict(self):
return {
k: str(v) if isinstance(v, uuid.UUID) else v
for k, v in self.__dict__.items()
}
方法 4: __slots__
を使用する場合
@dataclass(slots=True)
を使用している場合:
@dataclass(slots=True)
class MessageHeader:
message_id: uuid.UUID
count: int
def to_dict(self):
return {
'message_id': str(self.message_id),
'count': self.count
}
パフォーマンス比較
各方法のパフォーマンス比較(10,000回実行した場合の時間):
方法 | 実行時間(秒) |
---|---|
__dict__ 直接使用 | 約 0.006 |
辞書内包表記 | 約 0.008 |
dataclasses.asdict() 使用 | 約 0.071 |
INFO
単純な変換には __dict__
を直接操作する方法が最も高速ですが、asdict()
はより複雑なデータ構造を適切に処理します。
まとめ
Python dataclass を文字列リテラルの辞書に変換するには、以下の方法がおすすめです:
- シンプルで読みやすい場合:
asdict()
を使用した辞書内包表記 - パフォーマンス重視の場合:
__dict__
を直接操作 __slots__
使用時: 明示的に各フィールドを変換
用途に応じて最適な方法を選択してください。データ構造が複雑な場合は asdict()
を、シンプルでパフォーマンスが重要な場合は __dict__
の直接操作を推奨します。