Python辞書のキー名を変更する方法完全ガイド:効率的なリネーム・置換テクニック

 

Python辞書を扱う際、「キー名を変更したい」という場面は頻繁に発生します。APIの仕様変更、データベースカラム名の変更、日本語キーの英語化など、様々なケースで辞書のキー名変更が必要になります。本記事では、辞書のキー名を安全かつ効率的に変更する方法を、実践的なサンプルコードとともに詳しく解説します。

基本的なキー名変更方法

pop()とセットを使った標準的な方法

最も一般的で安全な方法です。

user_data = {'old_name': '太郎', 'age': 25, 'city': '東京'}

# キー名を変更
user_data['new_name'] = user_data.pop('old_name')
print(user_data)  # {'age': 25, 'city': '東京', 'new_name': '太郎'}

del文を使った方法

user_data = {'old_key': 'value', 'age': 25}

# 値を保存してからキーを削除
value = user_data['old_key']
del user_data['old_key']
user_data['new_key'] = value

print(user_data)  # {'age': 25, 'new_key': 'value'}

存在チェック付きの安全な変更

def rename_key(dictionary, old_key, new_key):
    """安全なキー名変更"""
    if old_key in dictionary:
        dictionary[new_key] = dictionary.pop(old_key)
        return True
    return False

user_data = {'name': '太郎', 'age': 25}
success = rename_key(user_data, 'name', 'username')
print(f"変更成功: {success}")  # True
print(user_data)  # {'age': 25, 'username': '太郎'}

複数キーの一括変更

辞書を使ったマッピング変更

original_data = {
    'fname': '太郎',
    'lname': '田中', 
    'yrs': 25,
    'loc': '東京'
}

# キー変更マッピング
key_mapping = {
    'fname': 'first_name',
    'lname': 'last_name',
    'yrs': 'age',
    'loc': 'location'
}

# 一括変更
for old_key, new_key in key_mapping.items():
    if old_key in original_data:
        original_data[new_key] = original_data.pop(old_key)

print(original_data)
# {'first_name': '太郎', 'last_name': '田中', 'age': 25, 'location': '東京'}

関数化した一括変更

def rename_keys(dictionary, mapping):
    """複数キーを一括変更"""
    for old_key, new_key in mapping.items():
        if old_key in dictionary:
            dictionary[new_key] = dictionary.pop(old_key)
    return dictionary

data = {'a': 1, 'b': 2, 'c': 3}
mapping = {'a': 'alpha', 'b': 'beta', 'c': 'gamma'}

result = rename_keys(data, mapping)
print(result)  # {'alpha': 1, 'beta': 2, 'gamma': 3}

リスト内包表記を使った新しい辞書作成

original = {'old_key1': 'value1', 'old_key2': 'value2', 'keep': 'value3'}

key_mapping = {'old_key1': 'new_key1', 'old_key2': 'new_key2'}

# 新しい辞書を作成
new_dict = {
    key_mapping.get(k, k): v 
    for k, v in original.items()
}

print(new_dict)  # {'new_key1': 'value1', 'new_key2': 'value2', 'keep': 'value3'}

条件付きキー名変更

パターンマッチングによる変更

import re

api_data = {
    'user_name': '太郎',
    'user_age': 25,
    'user_email': 'taro@example.com',
    'product_id': 123
}

# プレフィックスを削除
def remove_prefix(dictionary, prefix):
    new_dict = {}
    for key, value in dictionary.items():
        if key.startswith(prefix):
            new_key = key[len(prefix):]
            new_dict[new_key] = value
        else:
            new_dict[key] = value
    return new_dict

cleaned_data = remove_prefix(api_data, 'user_')
print(cleaned_data)
# {'name': '太郎', 'age': 25, 'email': 'taro@example.com', 'product_id': 123}

正規表現を使った高度な変更

import re

data = {
    'firstName': '太郎',
    'lastName': '田中',
    'phoneNumber': '090-1234-5678',
    'emailAddress': 'taro@example.com'
}

def camel_to_snake(dictionary):
    """キャメルケースをスネークケースに変更"""
    new_dict = {}
    for key, value in dictionary.items():
        # キャメルケースをスネークケースに変換
        snake_key = re.sub('([A-Z])', r'_\1', key).lower().lstrip('_')
        new_dict[snake_key] = value
    return new_dict

result = camel_to_snake(data)
print(result)
# {'first_name': '太郎', 'last_name': '田中', 'phone_number': '090-1234-5678', 'email_address': 'taro@example.com'}

値に基づくキー変更

grades = {
    'student_001': 85,
    'student_002': 92,  
    'student_003': 76,
    'student_004': 94
}

# 成績に基づいてキーを変更
def rename_by_grade(dictionary):
    new_dict = {}
    for key, grade in dictionary.items():
        if grade >= 90:
            new_key = key.replace('student', 'excellent_student')
        elif grade >= 80:
            new_key = key.replace('student', 'good_student')
        else:
            new_key = key.replace('student', 'average_student')
        new_dict[new_key] = grade
    return new_dict

result = rename_by_grade(grades)
print(result)
# {'good_student_001': 85, 'excellent_student_002': 92, 'average_student_003': 76, 'excellent_student_004': 94}

実践的な応用例

APIレスポンスのキー正規化

api_response = {
    'UserID': 123,
    'user-name': '太郎',
    'User_Email': 'taro@example.com',
    'phone_number': '090-1234-5678'
}

def normalize_keys(dictionary):
    """キーを統一形式に正規化"""
    normalized = {}
    for key, value in dictionary.items():
        # 全て小文字のスネークケースに統一
        normalized_key = re.sub(r'[-\s]+', '_', key)  # ハイフンとスペースをアンダースコアに
        normalized_key = re.sub('([A-Z])', r'_\1', normalized_key).lower()  # キャメルケースを変換
        normalized_key = normalized_key.strip('_')  # 前後のアンダースコア削除
        normalized[normalized_key] = value
    return normalized

result = normalize_keys(api_response)
print(result)
# {'user_i_d': 123, 'user_name': '太郎', 'user_email': 'taro@example.com', 'phone_number': '090-1234-5678'}

データベースマッピングでの活用

db_record = {
    'id': 1,
    'created_at': '2024-01-01',
    'updated_at': '2024-01-02',
    'user_name': '太郎',
    'user_status': 'active'
}

# データベースカラム名をアプリケーション用に変換
db_to_app_mapping = {
    'created_at': 'createdDate',
    'updated_at': 'updatedDate', 
    'user_name': 'userName',
    'user_status': 'status'
}

def convert_db_to_app(record, mapping):
    """DB形式からアプリ形式に変換"""
    converted = {}
    for key, value in record.items():
        new_key = mapping.get(key, key)
        converted[new_key] = value
    return converted

app_data = convert_db_to_app(db_record, db_to_app_mapping)
print(app_data)
# {'id': 1, 'createdDate': '2024-01-01', 'updatedDate': '2024-01-02', 'userName': '太郎', 'status': 'active'}

CSVヘッダーの正規化

csv_data = {
    '名前': '太郎',
    '年齢': 25,
    'メール アドレス': 'taro@example.com',
    '電話番号(携帯)': '090-1234-5678'
}

# 日本語ヘッダーを英語に変換
header_mapping = {
    '名前': 'name',
    '年齢': 'age', 
    'メール アドレス': 'email',
    '電話番号(携帯)': 'mobile_phone'
}

def localize_headers(data, mapping):
    """ヘッダーを英語化"""
    result = {}
    for key, value in data.items():
        english_key = mapping.get(key, key)
        result[english_key] = value
    return result

english_data = localize_headers(csv_data, header_mapping)
print(english_data)
# {'name': '太郎', 'age': 25, 'email': 'taro@example.com', 'mobile_phone': '090-1234-5678'}

ネストした辞書でのキー変更

深い階層のキー変更

nested_data = {
    'user_info': {
        'personal': {
            'old_name': '太郎',
            'old_age': 25
        },
        'contact': {
            'old_email': 'taro@example.com'
        }
    }
}

def rename_nested_keys(data, old_key, new_key):
    """ネストした辞書内のキーを再帰的に変更"""
    if isinstance(data, dict):
        new_data = {}
        for k, v in data.items():
            # キー名を変更
            new_k = new_key if k == old_key else k
            # 値が辞書の場合は再帰的に処理
            new_data[new_k] = rename_nested_keys(v, old_key, new_key)
        return new_data
    return data

# 全ての'old_name'を'name'に変更
result = rename_nested_keys(nested_data, 'old_name', 'name')
print(result)

複数レベルでの一括変更

complex_data = {
    'level1': {
        'oldKey1': 'value1',
        'level2': {
            'oldKey2': 'value2',
            'oldKey3': 'value3'
        }
    }
}

def bulk_rename_nested(data, mapping):
    """ネストした辞書で複数キーを一括変更"""
    if isinstance(data, dict):
        new_data = {}
        for key, value in data.items():
            new_key = mapping.get(key, key)
            new_data[new_key] = bulk_rename_nested(value, mapping)
        return new_data
    return data

key_changes = {
    'oldKey1': 'newKey1',
    'oldKey2': 'newKey2', 
    'oldKey3': 'newKey3'
}

result = bulk_rename_nested(complex_data, key_changes)
print(result)

パフォーマンス比較

各手法の速度比較

import timeit

# テストデータの準備
large_dict = {f'old_key_{i}': i for i in range(10000)}
mapping = {f'old_key_{i}': f'new_key_{i}' for i in range(10000)}

# 方法1: pop()を使用
def method1(data, mapping):
    for old_key, new_key in mapping.items():
        if old_key in data:
            data[new_key] = data.pop(old_key)

# 方法2: 新しい辞書を作成
def method2(data, mapping):
    return {mapping.get(k, k): v for k, v in data.items()}

# 方法3: del文を使用
def method3(data, mapping):
    for old_key, new_key in mapping.items():
        if old_key in data:
            value = data[old_key]
            del data[old_key]
            data[new_key] = value

# パフォーマンステスト(小規模データで実行)
small_dict = {f'old_{i}': i for i in range(100)}
small_mapping = {f'old_{i}': f'new_{i}' for i in range(100)}

time1 = timeit.timeit(lambda: method1(small_dict.copy(), small_mapping), number=1000)
time2 = timeit.timeit(lambda: method2(small_dict, small_mapping), number=1000)

print(f"pop()方式: {time1:.4f}秒")
print(f"新辞書作成: {time2:.4f}秒")

エラーハンドリングとベストプラクティス

安全なキー変更の実装

def safe_rename_key(dictionary, old_key, new_key, overwrite=False):
    """安全なキー名変更(エラーハンドリング付き)"""
    # 入力チェック
    if not isinstance(dictionary, dict):
        raise TypeError("第一引数は辞書である必要があります")
    
    # 元キーの存在チェック
    if old_key not in dictionary:
        return False, f"キー '{old_key}' が存在しません"
    
    # 新キーの重複チェック
    if new_key in dictionary and not overwrite:
        return False, f"キー '{new_key}' は既に存在します"
    
    # キー変更実行
    try:
        dictionary[new_key] = dictionary.pop(old_key)
        return True, f"キー '{old_key}' を '{new_key}' に変更しました"
    except Exception as e:
        return False, f"変更中にエラー: {e}"

# 使用例
data = {'name': '太郎', 'age': 25}
success, message = safe_rename_key(data, 'name', 'username')
print(f"{message}")  # キー 'name' を 'username' に変更しました

# 重複チェック
success, message = safe_rename_key(data, 'age', 'username')
print(f"{message}")  # キー 'username' は既に存在します

バックアップ機能付きの変更

def rename_with_backup(dictionary, old_key, new_key):
    """バックアップ機能付きキー変更"""
    # 元の辞書をバックアップ
    backup = dictionary.copy()
    
    try:
        if old_key in dictionary:
            dictionary[new_key] = dictionary.pop(old_key)
            return True, backup
        else:
            return False, None
    except Exception:
        # エラー時は元の状態に戻す
        dictionary.clear()
        dictionary.update(backup)
        return False, None

# 使用例
data = {'important_data': '重要な値'}
success, backup = rename_with_backup(data, 'important_data', 'crucial_data')

if success:
    print("変更成功:", data)
else:
    print("変更失敗、元の状態に復元:", data)

型安全な変更

from typing import Dict, Any, Optional, Tuple

def type_safe_rename(
    dictionary: Dict[str, Any], 
    old_key: str, 
    new_key: str
) -> Tuple[bool, Optional[str]]:
    """型安全なキー名変更"""
    if not all(isinstance(k, str) for k in [old_key, new_key]):
        return False, "キー名は文字列である必要があります"
    
    if old_key not in dictionary:
        return False, f"キー '{old_key}' が見つかりません"
    
    dictionary[new_key] = dictionary.pop(old_key)
    return True, None

# 使用例
user_data: Dict[str, Any] = {'name': '太郎', 'age': 25}
success, error = type_safe_rename(user_data, 'name', 'username')

if success:
    print("変更成功:", user_data)
else:
    print("エラー:", error)

まとめ

Python辞書のキー名変更には、様々な方法とテクニックがあります。状況に応じて最適な方法を選択することが重要です。

基本的な変更手法

  • pop()メソッドが最も安全で推奨される方法
  • del文も使えるが、pop()の方が簡潔

複数キー変更

  • マッピング辞書を使った一括変更が効率的
  • 新しい辞書作成は元の辞書を保持したい場合に有効

実用的なポイント

  • エラーハンドリングを必ず実装
  • 大量データではパフォーマンスを考慮
  • 型チェックでバグを防止

注意すべき点

  • キーの重複チェック
  • ネストした辞書での再帰処理
  • バックアップ機能の実装

これらの技術を適切に組み合わせることで、安全で効率的な辞書のキー名変更を実現できるでしょう。

■プロンプトだけでオリジナルアプリを開発・公開してみた!!

■AI時代の第一歩!「AI駆動開発コース」はじめました!

テックジム東京本校で先行開始。

■テックジム東京本校

「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。

<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。

<月1開催>放送作家による映像ディレクター養成講座

<オンライン無料>ゼロから始めるPython爆速講座