はじめに¶
リストのsort()
メソッドを使ったときに,Pythonの値渡しと参照渡しについて調べることになったのでまとめる.
以下の3つに注意が必要.
Pythonにおいて,
sort()
は破壊的メソッドであるlist
型は変更可能な型(mutable)である- mutableなオブジェクトは参照渡しをする
sort
は破壊的メソッドである¶
「破壊的メソッド」という単語は,PythonというよりはRuby業界の用語の気がするが,わかりやすので使わせてもらう.
破壊的メソッドは,そのメソッドが対象とするオブジェクトの値そのものを変更してしまうようなメソッドの事.
hoge = [3,1,5,2,9,8,6,4,7]
hoge.sort()
print(hoge)
元のリストオブジェクトの値そのものが変更される.
list
型は変更可能な型(Mutable)である¶
まず,mutableとその対をなすimmutableという概念について説明する.オブジェクトの種類を表す概念であり,「list
型はmutaleなオブジェクトである」というような文脈で用いられる.
簡単に言えば,
- mutaleなオブジェクト:値を変更できるオブジェクト(
list
,dict
,set
等) - immutableなオブジェクト:値を変更できないオブジェクト(
int
,float
,str
等)
である.
定数という概念がないPythonにおいて,値を変更できないオブジェクトなんて存在するのかと思うかもしれない.
ここで言う「値を変更できない」とは,生成時に確保されたメモリ領域が保持する値を後から変更できないという意味である.
実際に見てみるのがはやい.
#int型はimmutableなオブジェクトである
#int型のオブジェクトを生成
hoge_1 = int(5)
#idでメモリ領域のアドレスを取得
print("First check:", id(hoge_1))
#見かけ上の値の変更を試みる
hoge_1 = int(10)
print("Second check:", id(hoge_1))
このように見かけ上は値が置き換わっているが,実際には新しい領域を確保している.つまり最初のメモリ領域の値は変更できない.
#list型はmutableなオブジェクトである
#list型のオブジェクトを生成
hoge_list = [1,2,3,4,5]
#idでメモリ領域のアドレスを取得
print("First check:", id(hoge_list))
#値の変更を試みる
hoge_list[4] = 7
print("Second check:", id(hoge_list))
メモリ領域のアドレスは変わらないので,値の変更に成功している.
mutableなオブジェクトは参照渡しをする¶
実は,immutableなオブジェクトも関数や変数に値を渡す場合は参照渡しをしている.
ただ,その後に変数の値が変更されるタイミングでメモリ領域を新しく確保するので,見かけ上値渡しに見える.
hoge_1 = int(4)
print("First check:", id(hoge_1))
hoge_2 = hoge_1
print("Second check:", id(hoge_2))
hoge_2 = int(6)
print("Third check:", id(hoge_2))
一方,mutableなオブジェクトであるlist
の場合は以下のようになる.
hoge_list_1 = [1, 3, 5]
print("First check:", id(hoge_list_1))
hoge_list_2 = hoge_list_1
print("Second check:", id(hoge_list_2))
hoge_list_2[0] = 7
print("Third check:", id(hoge_list_2))
#値そのものを確認
print("----------")
print("hoge_list_1:", hoge_list_1)
print("hoge_list_2:", hoge_list_2)
このように,hoge_list_2
の値を変更するとhoge_list_1
の値も変更される.
つまり¶
なにが言いたかったかというと以下のような挙動が起こりますよってこと.
x = [4, 2, 9, 5, 1, 8, 3, 7, 6]
y = x
z = y
z.sort()
print("x:",x)
print("y:",y)
print("z:",z)
説明は不要かと思われる.
こんなこともあるって頭に入れておく必要があるな.