BBH
-Biz Branding Hub-
投稿日 : 
2019/11/15
更新日 : 
2019/11/15

Pythonでは型によって値渡しと参照渡しが異なる

Pythonにおける値渡し

Pythonでは型によって変数や関数へのデータの受け渡しが「値渡し」と「参照渡し」に異なります。
ある型の場合は値渡しになるが、別の型では参照渡しになることがあるということです。
例えば以下の例を見てみます。

python

def add(a):
    a += 1
    return a

val = 10
res = add(val)
print('val = ' + str(val))
print('res = ' + str(res))

実行結果は以下のようになります。

python

val = 10
res = 11

上記の例では関数add()の中で、呼び元の変数valをaとして受け取り、受け取った変数aに変更を加えています。
そして、その結果を呼び元に返却するということをしています。
しかし、呼び元でvalをprintしてみるとわかるように、関数の実行前後で値は10のまま変わっていません。
これは、valが関数add()に値渡しで渡されているためです。

値渡しでは、呼び元の値が別の領域にコピーされて渡されます。
つまり、値自体は同じなのですが、実体は別のものが渡されるということになります。
そのため、その変数をいくら関数add()内で変更しても、呼び元のvalには影響が出ないのです。

Pythonにおける参照渡し

では、次の例を見てみましょう。

python

def add(a):
    a.append(4)
    return a

val = [1, 2, 3]
res = add(val)
print('val = ' + str(val))
print('res = ' + str(res))

先ほどの例とほぼ同じです。
異なるのは、valのデータ型がintからlistになっていることです。

実行結果は以下のようになります。

python

val = [1, 2, 3, 4]
res = [1, 2, 3, 4]

先ほどの例と異なる結果が出ました。
変更を行っているのは関数内なのにも関わらず、呼び元の変数も変わってしまっています。
これは、valが関数add()に参照渡しで渡されていることが原因です。

値渡しは、呼び元の変数をコピーして関数に渡していました。
値は同じですが、実体は異なります。
一方参照渡しというのは、変数そのものを渡します。
正確には、変数のアドレスを渡します。
なので、関数内の変更も呼び元の変数そのものに影響するわけです。

変更不可(immutable)な型と変更可能(mutable)な型

なぜ、同じ処理をしているのに挙動が異なるのでしょうか。
その原因は、データ型にあります。
最初の例ではint型で次の例ではlist型を用いています。
この差が、値渡しと参照渡しの違いを引き起こしています。

Pythonでは、データの方によって値渡しか参照渡しが異なります。
immutableな型は値渡しされ、muttableな型は値渡しされます。
具体的には、int、str、boolなどはimmutableな型で、listやdict、classなどはmuutableな型となります。

今回はあくまで使う側の立場からmuttableとimuttableの違いを説明しましたが、内部の挙動としては以下のようになっているようです。


変数に代入されているオブジェクトそれ自体を変更可能なものがmuttable、変更不可のものがimmutableと呼ぶようです。

Profile

管理人プロフィール

都内でITエンジニアをやってます。
変遷:中規模SES→独立系SIer→Webサービス内製開発
使用技術はその時々でバラバラですが、C#、AWSが長いです。
どちらかと言うとバックエンドより開発が多かったです。
顧客との折衝や要件定義、マネジメント(10名弱程度)の経験あり。
最近はJava+SpringBootがメイン。

Recommend