はじめに
Python では、辞書 (dictionary) はキーと値のペアを格納できる便利なデータ構造です。時には、辞書内の最大値のキーを見つける必要がある場合があります。このチャレンジでは、辞書を引数として受け取り、その辞書内の最大値のキーを返す関数を作成します。
基本関数の作成
まずは関数の核心部分を作成しましょう。段階的に構築していきます。最初に、key_of_max.py という名前のファイルを作成します。LabEx の組み込みコードエディタを使用するか、nano や vim のようなターミナルベースのエディタを使用することができます。key_of_max.py の中に、以下のコードを追加します。

def key_of_max(d):
"""
辞書 'd' 内の最大値に関連付けられたキーを返します。
複数のキーが最大値を共有する場合、そのいずれかが返されます。
"""
return max(d, key=d.get)
これを詳しく見ていきましょう。
def key_of_max(d):: これはkey_of_maxという名前の関数を定義しています。この関数は 1 つの引数dを受け取り、これは操作対象の辞書を表します。return max(d, key=d.get): これが関数の核心部分です。少しずつ分析してみましょう。max(d,...): 組み込みのmax()関数は最大の要素を見つけます。デフォルトでは、max()に辞書を渡すと、最大の _キー_(アルファベット順)を見つけます。しかし、私たちは最大の 値 に 関連付けられた キーを求めています。key=d.get: これが重要な部分です。key引数はmax()に要素の比較方法を指示します。d.getは辞書のメソッドです。d.get(some_key)を呼び出すと、some_keyに関連付けられた 値 が返されます。key=d.getと設定することで、max()に「辞書dの要素を 値 で比較し、キーではなく比較してください」と指示しています。その結果、max()関数は最大値に対応する キー を返します。
空の辞書のケースの処理
現在の関数には問題があります。入力の辞書 d が空の場合、関数はクラッシュします。これを修正しましょう。key_of_max.py を以下のように変更します。
def key_of_max(d):
"""
辞書 'd' 内の最大値に関連付けられたキーを返します。
複数のキーが最大値を共有する場合、そのいずれかが返されます。
"""
if not d: ## Check if the dictionary is empty
return None
return max(d, key=d.get)
追加された行は以下のような処理を行います。
if not d:: Python では、空の辞書は「偽 (falsy)」と見なされます。このif文は辞書dが空かどうかをチェックします。return None: 辞書が空の場合、最大値は存在しないため、Noneを返します。これは Python で値が存在しないことを示す標準的な方法です。これにより、max()関数がエラーを発生させるのを防ぎます。
これは堅牢なコードを書く上で重要なステップです。常にエッジケースを考慮しましょう!
単体テストの作成:基本的なテスト
では、関数が正しく動作することを確認するためにいくつかのテストを書きましょう。Python の unittest モジュールを使用します。test_key_of_max.py という名前の新しいファイルを作成し、以下のコードを追加します。
import unittest
from key_of_max import key_of_max ## Import our function
class TestKeyOfMax(unittest.TestCase):
def test_basic_case(self):
self.assertEqual(key_of_max({'a': 4, 'b': 0, 'c': 13}), 'c')
def test_another_case(self):
self.assertEqual(key_of_max({'apple': 10, 'banana': 5, 'orange': 10}), 'apple')
if __name__ == '__main__':
unittest.main()
説明:
import unittest: テストフレームワークをインポートします。from key_of_max import key_of_max: テスト対象の関数をインポートします。class TestKeyOfMax(unittest.TestCase):: テストクラス を定義します。テストクラスは関連するテストをまとめます。def test_basic_case(self):: テストメソッド を定義します。各テストメソッドは関数の特定の側面をチェックします。テストメソッド名は必ずtest_で始める必要があります。self.assertEqual(...): これは アサーション です。2 つの値が等しいかどうかをチェックします。等しくない場合、テストは失敗します。この場合、key_of_max({'a': 4, 'b': 0, 'c': 13})が'c'を返すかどうかをチェックしています。def test_another_case(self):: 最大値のキーが一意でない場合を検証するための別のテストケースを追加しました。if __name__ == '__main__': unittest.main(): この標準的な Python の慣用句は、スクリプトを直接実行するときにテストを実行します(例:python3 test_key_of_max.py)。
ターミナルからテストを実行します:python3 test_key_of_max.py。2 つのテストが合格したことを示す出力が表示されるはずです。
python3 test_key_of_max.py
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
空の辞書のテスト(エッジケース)
空の辞書のケースに特化したテストを追加しましょう。test_key_of_max.py の TestKeyOfMax クラスに以下のメソッドを追加します。
def test_empty_dictionary(self):
self.assertIsNone(key_of_max({}))
self.assertIsNone(...): このアサーションは、値が具体的にNoneであるかどうかをチェックします。これは重要です。なぜなら、self.assertEqual(..., None)はNoneに 評価される ものに対して合格する可能性がありますが、実際にNoneではない場合もあります。assertIsNoneはより厳密です。
再度テストを実行します(python3 test_key_of_max.py)。3 つのテスト(2 つの基本テストと空の辞書のテスト)がすべて合格するはずです。
python3 test_key_of_max.py
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK
すべての値が負の場合のテスト
最後のテストとして、辞書内のすべての値が負の場合を扱いましょう。TestKeyOfMax に以下のメソッドを追加します。
def test_all_negative_values(self):
self.assertEqual(key_of_max({'x': -5, 'y': -2, 'z': -10}), 'y')
このテストは、関数が「最も負の値が小さい」(この場合の最大値)を正しく識別し、それに関連付けられたキーを返すことを保証します。
最後に一度テストを実行しましょう(python3 test_key_of_max.py)。4 つのテストすべてが合格するはずです。これにより、関数が正しく動作していることを高い確信を持って確認できます。
完成した test_key_of_max.py は以下のようになるはずです。
import unittest
from key_of_max import key_of_max
class TestKeyOfMax(unittest.TestCase):
def test_basic_case(self):
self.assertEqual(key_of_max({'a': 4, 'b': 0, 'c': 13}), 'c')
def test_another_case(self):
self.assertEqual(key_of_max({'apple': 10, 'banana': 5, 'orange': 10}), 'apple')
def test_empty_dictionary(self):
self.assertIsNone(key_of_max({}))
def test_all_negative_values(self):
self.assertEqual(key_of_max({'x': -5, 'y': -2, 'z': -10}), 'y')
if __name__ == '__main__':
unittest.main()
再度テストを実行します(python3 test_key_of_max.py)。4 つのテストすべてが合格するはずです。これにより、関数が正しく動作していることを高い確信を持って確認できます。
python3 test_key_of_max.py
----------------------------------------------------------------------
Ran 4 tests in 0.000s
OK
まとめ
この実験では、辞書内の最大値に関連付けられたキーを見つける Python 関数 key_of_max を作成しました。max() 関数をカスタムの key 引数とともに使用する方法を学び、空の辞書という重要なエッジケースを処理しました。また、unittest モジュールを使用して基本的なケース、空の辞書、すべての値が負の辞書などを網羅した包括的な単体テストを作成しました。このような機能コードと包括的なテストの組み合わせは、良好なソフトウェア開発の実践を示しています。