1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Python(Django) x Docker x AWSAdvent Calendar 2023

Day 15

【Python】デフォルト引数を使うときは、引数の順序と可変オブジェクトに注意

Posted at

概要

Pythonでデフォルト引数を使ってみたので紹介。

デフォルト引数では、関数を呼び出す際に引数が提供されなかった場合に、デフォルトで使える値が設定できます。
要は、「オプションのパラメーター」になる、ということです。

サンプルコードでみてみるのが早いと思うので実際に以下のように実行しました。

サンプルコード

def add_and_display_list_items(items_list, new_item="apple"):
    items_list.append(new_item)
    print("My Fruit List:", items_list)

my_list = []
add_and_display_list_items(my_list)
add_and_display_list_items(my_list, "banana")
add_and_display_list_items(my_list, "lemon")

# 出力
# My Fruit List: ['apple']
# My Fruit List: ['apple', 'banana']
# My Fruit List: ['apple', 'banana', 'lemon']

解説

デフォルト引数new_item="apple"は、もし関数が呼び出された際にnew_itemが指定されなかった場合、関数内部で使用される値として"apple"が代入されることを意味しています。

実際に、一つ目の呼び出しではappleだけであり、これでデフォルト引数の役割がわかりますね。
二つ目以降では、各呼び出し後にリストが更新されていることがわかります。

注意点1:引数の順序

デフォルト引数は通常の引数より前におくとエラーになります。

def add_and_display_list_items(new_item="apple", items_list):
    items_list.append(new_item)
    print("My Fruit List:", items_list)

my_list = []
add_and_display_list_items(my_list)
add_and_display_list_items("banana", my_list)
add_and_display_list_items("lemon", my_list)

# 出力
#    def add_and_display_list_items(new_item="apple", items_list):
#                                                     ^^^^^^^^^^
# SyntaxError: non-default argument follows default argument

注意点2:可変オブジェクト(リスト、辞書など)を扱う場合

二つ目の注意点は可変オブジェクト(ミュータブル)を扱うケースです。
Pythonでは、関数が定義された際にデフォルト引数が一度だけ評価され、その後そのオブジェクトが関数呼び出しの際には再利用されます。

def add_to_list(value, my_list=[]):
    print(my_list)
    my_list.append(value)
    return my_list

print(add_to_list(1))
print(add_to_list(2))

# 出力
# []
# [1]
# [1]
# [1, 2]

上記の通り、my_listが更新されてしまっていることがわかります。
順序にすると以下の通りです。

  1. 最初のadd_to_list(1)呼び出しでは、デフォルト引数のリストmy_listは空のリスト[]として作成され、表示されます。
  2. my_listvalueが追加されて[1]となります。
  3. 次のadd_to_list(2)呼び出しでは、再びデフォルト引数のmy_listは前の呼び出しで変更されたリスト[1]を使います。

このような挙動を防ぐためには、代わりにNoneを使い、関数内で新しいオブジェクトを作成すると良いです。

def add_to_list(value, my_list=None):
    if my_list is None:
        my_list = []
    print(my_list)
    my_list.append(value)
    return my_list

print(add_to_list(1))
print(add_to_list(2))

# 出力
# []
# [1]
# []
# [2]

参考

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?