Pythonが関数に引数を渡す方法を理解することは、データの予期しない変更を防ぎ、コードを正しく設計するために非常に重要です。
CやJavaなどの従来のプログラミング言語では、値渡し(copy by value)や参照渡し(copy by reference)が使われます。しかし、Pythonは異なるモデルを持っています — オブジェクト参照による呼び出し(時々「共有による呼び出し」と呼ばれます)。
多くの開発者は、Pythonが常に引数を参照として、または値として渡すと思い込んでいます。これにより、変更可能なオブジェクトが予期せず呼び出し元のコードで修正される状況が避けられません。
Pythonでは、関数のパラメータの値は、関数に渡されるオブジェクトへの参照です。これは次のことを意味します:
例:
# list - 変更可能(mutable) def add_item(lst): lst.append(42) my_list = [1, 2, 3] add_item(my_list) print(my_list) # [1, 2, 3, 42] # int - 変更不可能(immutable) def add_num(x): x = x + 1 num = 10 add_num(num) print(num) # 10
主な特徴:
Pythonでは常に引数が参照として渡されますか?
いいえ、Pythonではオブジェクトへの参照が渡され、そのオブジェクトの挙動は、変更可能かどうかに依存します。変更不可能なオブジェクトは変更時に常に新しいオブジェクトが作成されます。
関数内で変更可能な引数を再割り当てし、それを外部のオブジェクトに影響を与えることはできますか?
いいえ。関数内でパラメータに新しい値を割り当てても、外部のオブジェクトには何も変わりません — あなたは単にローカル参照を変更しているだけです。
例:
def reassign_list(lst): lst = [99, 100] my_list = [1, 2, 3] reassign_list(my_list) print(my_list) # [1, 2, 3]
デフォルトでlistを受け取る関数が再呼び出しで奇妙に動作するのはなぜですか?
デフォルト値は関数定義時に一度だけ作成され、その後変更されると(例えば、要素を追加するなど)、すべての後続の呼び出しで変更されます。
def add_element(x, cache=[]): cache.append(x) return cache print(add_element(1)) # [1] print(add_element(2)) # [1, 2]
プログラマーは関数にリストを渡し、元のリストが変更されないことを期待しますが、関数は要素を追加します。
利点:
欠点:
プログラマーは、元のリストを変更せずに何かを返す必要があるときに、関数内で明示的にリストをコピーします:
def process_data(data): data = data.copy() # または list(data) # コピーで安全に作業 data.append('レポート') return data
利点:
欠点: