LoginSignup
0
0

More than 1 year has passed since last update.

関数内で配列を書き換えた際の関数呼び出し後の挙動まとめ(python)

Last updated at Posted at 2021-05-21

1.配列を関数内で書き換えたとき、関数呼び出し後に配列はどうなる?

以下の状況を想定する。

  • 関数test(array)に配列arrayを引数として渡す
  • 関数test(array)内で、何らかの方法で配列の要素を増やす
  • 関数test(array)呼び出し後に、配列arrayの中身を確認する

ここでは、関数呼び出し後にarrayの中身が書き変わっているかどうかを考える。

コードで書くと次のようになる。

def test(array):
    #ここでarrayに[3]を追加して[1,2,3]にする
    return sum(array)

array = [1,2]
ans = test(array)
print(array) # 結果は[1,2]か?、それとも[1,2,3]か?
print(ans) #6

今回は、

  • 関数呼び出し後にarrayの中身が書き変わってしまうパターン
  • 関数呼び出し後もarrayの中身が書き変わらないパターン

をそれぞれ2つずつ紹介する。

2. 関数呼び出し後にarrayの中身が書き変わってしまうパターン

2.1. 書き変わるパターンその1 : append()を使う

def test(array):
    array.append(3) #aの要素を増やす
    return sum(array)

array = [1,2]
ans = test(array)
print(array) #[1,2,3]と表示される(!)
print(ans) #6

関数test(array)を実行すると、arrayが書き変わってしまうことがわかる。これは、関数test(array)に対して配列arrayが参照渡しされていることが原因である。関数test()は配列arrayそのものを参照するため、関数内でappendすると、関数の呼び出し後にはarrayは書き変わってしまう。

2.2. 書き変わるパターンその2 : +=を使う

def test(array):
    array += [3] #aの要素を増やす
    return sum(array)

array = [1,2]
ans = test(array)
print(array) #[1,2,3]と表示される(!)
print(ans) #6

この場合も同様。関数の呼び出し後にはarrayは書き変わってしまう。
+=は実質append()と同じで、arrayの要素を一つ追加すると考えてよい。

3. 関数呼び出し後もarrayの中身が書き変わらないパターン

上記のような、関数内での配列操作が外に伝わってしまう状況を回避するには、要は関数内でarrayのコピーを作ってから作業を始めれば良い。

3.1. 書き変わらないパターンその1 : copy()を使う

pythonでは、配列の中身を丸ごと値渡しでコピーするcopy.copy()copy.deepcopy()が用意されている。それぞれ、いわゆる「浅いコピー」と「深いコピー」に対応する。よくわからなければとりあえずdeepcopy()を使っておけば間違いない(たぶん…)。

import copy
def test(array):
    array = copy.deepcopy(array)
    array = array + [3] #aの要素を増やす
    return sum(array)

array = [1,2]
ans = test(array)
print(array) #[1,2]と表示される
print(ans) #6

確かに、関数呼び出し後もarrayの中身は書き変わっていないことがわかる。

3.2. 書き変わらないパターンその2 : array = array + [3]とする

意外にも、array = array + [3]としても要件を満たすことができる。

def test(array):
    array = array + [3] #aの要素を増やす
    return sum(array)

array = [1,2]
ans = test(array)
print(array) #[1,2]と表示される
print(ans) #6

確かにarray = array + [3]とした場合でも、関数呼び出し後もarrayの中身は書き変わっていないことがわかる。

この結果は、array += [3]を用いた場合と対称的である(2.2.節参照)。おそらく、array += [3]とした場合はもとの配列に要素がappend()されるのに対し、array = array + [3]とした場合は新たに配列が確保されることが挙動の違いを生んでいるものと思われる。紛らわしい!

4. まとめ

書き変わってほしくない配列はとりあえずdeepcopy()しよう。

array = array + [3]array += [3]で挙動が異なるのが大変紛らわしい。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0