3.4 関数の引数
Pythonの関数は、非常に柔軟な引数の受け渡しが可能です。しかし、その柔軟さゆえに、正しいルールを理解していないと予期せぬエラーやバグを引き起こす原因にもなります。
本記事では、「3.4 関数の引数」として、Pythonにおける関数の引数の定義と渡し方のルール、そして実践的なベストプラクティスを解説します。
1. 位置引数とキーワード引数
Section titled “1. 位置引数とキーワード引数”関数を呼び出す際、引数を渡す方法には主に2種類あります。
- 位置引数 (Positional Arguments): 関数定義の順番通りに値を渡す方法です。
- キーワード引数 (Keyword Arguments):
引数名=値の形式で、名前を指定して値を渡す方法です。順番を気にせず渡すことができ、可読性が向上します。
def greet(name, message): print(f"{message}, {name}!")
# 位置引数による呼び出しgreet("Alice", "Hello") # 出力: Hello, Alice!
# キーワード引数による呼び出し(順番を逆にしてもOK)greet(message="Hi", name="Bob") # 出力: Hi, Bob!【注意点】 位置引数とキーワード引数を混在させる場合は、必ず位置引数を先に記述する必要があります(例: greet("Alice", message="Hello") はOKですが、greet(name="Alice", "Hello") は SyntaxError になります)。
2. デフォルト引数と「ミュータブルなデフォルト値」の罠
Section titled “2. デフォルト引数と「ミュータブルなデフォルト値」の罠”関数の定義時に 引数名=デフォルト値 と指定することで、呼び出し時にその引数が省略された場合に使われるデフォルトの値を設定できます。
🚨 注意:デフォルト値にリストや辞書(ミュータブル)を使ってはいけない
Section titled “🚨 注意:デフォルト値にリストや辞書(ミュータブル)を使ってはいけない”リストや辞書など、変更可能な(ミュータブルな)オブジェクトをデフォルト値に指定すると、関数が定義された時点でオブジェクトが1度だけ作成され、その後の呼び出しでずっと使い回されてしまうという有名な罠があります。
# 悪い例:デフォルト引数に空リストを指定def add_item(item, target_list=[]): target_list.append(item) return target_list
print(add_item("apple")) # ['apple']print(add_item("banana")) # ['apple', 'banana'] <- 空リストからスタートしない!正しい対処法: デフォルト値には不変(イミュータブル)な None を指定し、関数の中で初期化します。
# 良い例:Noneを使用して関数内で初期化def add_item(item, target_list=None): if target_list is None: target_list = [] target_list.append(item) return target_list3. 可変長引数 (*args と kwargs)
Section titled “3. 可変長引数 (*args と kwargs)”任意の数の引数を受け取りたい場合は、可変長引数を使用します。
*args: 任意の数の位置引数をタプルとして受け取ります。kwargs: 任意の数のキーワード引数を辞書として受け取ります。
def make_profile(name, *args, **kwargs): print(f"Name: {name}") print(f"Other Positional: {args}") print(f"Keyword Args: {kwargs}")
make_profile("Charlie", 25, "Engineer", city="Tokyo", hobby="Tennis")# 出力:# Name: Charlie# Other Positional: (25, 'Engineer')# Keyword Args: {'city': 'Tokyo', 'hobby': 'Tennis'}4. 位置専用引数 (/) と キーワード専用引数 (*)
Section titled “4. 位置専用引数 (/) と キーワード専用引数 (*)”Pythonの関数定義をより厳格にし、APIの使い勝手を良くするための機能です。
4.1 キーワード専用引数 (*)
Section titled “4.1 キーワード専用引数 (*)”* または *args より後ろに定義された引数は、必ずキーワード引数として渡さなければなりません。これにより、引数の意味を呼び出し側で明確にさせることができます。
# サーバーの起動関数。portとdebugは必ずキーワードで指定させたいdef run_server(host, *, port=8080, debug=False): pass
run_server("localhost", port=3000, debug=True) # OK# run_server("localhost", 3000, True) # TypeError!4.2 位置専用引数 (/) [Python 3.8以降]
Section titled “4.2 位置専用引数 (/) [Python 3.8以降]”/ より前に定義された引数は、必ず位置引数として渡さなければなりません。キーワードを指定して渡すことはできません。引数名に特別な意味がなく、順番だけが重要な組み込み関数(len(obj) など)のような振る舞いを自作の関数にも持たせることができます。
def power(base, exp, /): return base ** exp
power(2, 3) # OK# power(base=2, exp=3) # TypeError!