Pythonの参照渡しについて調べていると以下のような内容の記事が見つかったりします。
間違っている記事の内容
Q:Pythonで関数に渡した引数を関数内で変更すると関数を抜けたとき渡した変数の値が変わっていたり変わっていなかったりするがどういうこと?
A:引数がイミュータブルなオブジェクトかミュータブルなオブジェクトかで動作が変わる。
* イミュータブル:値はそのまま
* ミュータブル:値が変更される
つまり、イミュータブルなら値渡しでミュータブルなら参照渡しということですね。
値渡しと参照渡しについては以下を参照。
https://wa3.i-3-i.info/diff345programming.html
実際は?
@shiracamus (しらかみゅ) さんにコメントいただいた通りです。
Pythonは参照渡し出来ない言語であり、すべて値渡しです。
上記FAQにある
出力引数のある関数 (参照渡し) はどのように書きますか?
前提として、Python では引数は代入によって渡されます。代入はオブジェクトへの参照を作るだけなので、呼び出し元と呼び出し先にある引数名の間にエイリアスはありませんし、参照渡しそれ自体はありません。
ということですね。
なぜ参照渡しが存在すると勘違いするのか?
過去の私のような過ちが発生するのはなぜでしょう?
先ほどのFAQにて続きで
望む効果を得るためには幾つかの方法があります。
とあり、その方法4にて
def func3(args):
args['a'] = 'new-value' # args is a mutable dictionary
args['b'] = args['b'] + 1 # change it in-place
args = {'a': 'old-value', 'b': 99}
func3(args)
# {'a': 'new-value', 'b': 100}
と記載があります。
値渡しされる参照が参照しているオブジェクト自体を変更することで参照渡しもどきのような動作を起こしています。
ですが、実際は以下のように変数そのものに代入すれば元のオブジェクトには影響を与えず参照渡しではないことが確認できます。
def modify_list(lst):
lst = lst + [3] # 3を追加したリストを変数に代入
my_list = [1, 2]
modify_list(my_list)
print(my_list) # [1, 2] と出力され、元のオブジェクトに影響していない
実際は「参照の値渡し」が行われているわけですね。
方法4のような挙動を勘違いした過去の私のようなアホが冒頭に記載したような誤った内容を拡散してしまう要因だと思いました。
まとめ
Pythonに参照渡しは存在しない。すべて値渡しである。
改めてコメントいただきました@shiracamus (しらかみゅ) さんに感謝申し上げます。
これからも日々精進していきます。