検索ガイド -Search Guide-

単語と単語を空白で区切ることで AND 検索になります。
例: python デコレータ ('python' と 'デコレータ' 両方を含む記事を検索します)
単語の前に '-' を付けることで NOT 検索になります。
例: python -デコレータ ('python' は含むが 'デコレータ' は含まない記事を検索します)
" (ダブルクオート) で語句を囲むことで 完全一致検索になります。
例: "python data" 実装 ('python data' と '実装' 両方を含む記事を検索します。'python data 実装' の検索とは異なります。)
img_for_tre_tron
Tré Thộn を食べたことがありますか?
ベトナム・ビンズオン滞在中の方は是非注文して食べてみて!
絶対に美味しいです!
ホーチミン市内へも配達可能です。お問い合わせください。

Have you ever had "Tré Thộn" before?
If you're living at Bình Dương in Vietnam, you "must" try to order and eat it.
I'm sure you're very surprised how delicious it is!!
If you're in Hồ Chí Minh, you have a chance to get it too. Please call!!
>>

【Python 雑談・雑学】 Common Mistake: mutable なオブジェクトを関数のデフォルト値に使っちゃダメでしょ、の話 投稿一覧へ戻る

Published 2020年5月27日13:15 by mootaro23

SUPPORT UKRAINE

- Your indifference to the act of cruelty can thrive rogue nations like Russia -

悩んでいたので「どうしたの?」と声をかけたら ...


さて問題です。
print(a2) では何が出力されるでしょうか?


def enroll_class(name: str, attendee: str, attendees: list = []):
attendees.append(attendee)

return {
'name': name,
'attendee': attendee,
'attendees': attendees
}

a1 = enroll_class('math', 'Nana')
a2 = enroll_class('programming', 'Saki')

print(a2)



正解は


# {'name': 'programming', 'attendee': 'Saki', 'attendees': ['Nana', 'Saki']}




attendees リストの 'Nana' は何処から出てきたのでしょうか?


a2 = enroll_class('programming', 'Saki')
の何処にも 'Nana' は登場しないのに...


これは mutable なオブジェクトをデフォルト値として設定してしまったことから発生しています。


試しに、enroll_class() が呼び出されたときのそれぞれの attendees リストのアドレスを確認します。


def enroll_class(name: str, attendee: str, attendees: list = []):
print(id(attendees))
attendees.append(attendee)

return {
'name': name,
'attendee': attendee,
'attendees': attendees
}

a1 = enroll_class('math', 'Nana')
a2 = enroll_class('programming', 'Saki')

# 106499592
# 106499592




a1、a2 の呼び出しでまったく同じリストを指しています。


これは関数に設定したデフォルト値が、呼び出されたときではなく定義されたときに評価されるからです。


しかも、List は mutable なオブジェクトですから、a2 の呼び出し時における attendees.append() では a1 の呼び出し時のリストに値が追加されて返された結果、だったんです。


この問題への対処方法は2つあります。


1つは mutable なオブジェクトをデフォルト値としてセットするのを止めて (というか、mutable なオブジェクトをデフォルト値としてセットしてはいけません!)、常に呼び出し元から引数として渡すことです。


def enroll_class(name: str, attendee: str, attendees: list):
attendees.append(attendee)

return {
'name': name,
'attendee': attendee,
'attendees': attendees
}

a1 = enroll_class('math', 'Nana', [])
a2 = enroll_class('programming', 'Saki', [])

print(a2) # {'name': 'programming', 'attendee': 'Saki', 'attendees': ['Saki']}



もう1つは、デフォルト値としては None をセットし、関数内でチェックし対処する方法です。


def enroll_class(name: str, attendee: str, attendees: list = None):
if not attendees:
attendees = []
attendees.append(attendee)

return {
'name': name,
'attendee': attendee,
'attendees': attendees
}

a1 = enroll_class('math', 'Nana')
a2 = enroll_class('programming', 'Saki')

print(a2) # {'name': 'programming', 'attendee': 'Saki', 'attendees': ['Saki']}



自分が利用しているオブジェクトが immutable なのか mutable なのか、理解・把握しておくことはかなり重要です。