質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

280閲覧

if文で関数が使われたとき、その関数の引数は変化させたくない

Sigma1630

総合スコア36

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2018/05/26 13:26

編集2018/05/26 13:28

①引数に設定したリストの要素を全部2倍にする関数を作ります。
if文でその関数を用いたいですが、引数にしたリストはそのままにしたいのです。

具体例をあげます。

Python

1a = [1,2,3] 2 3def twice(ls): #リストの要素を全部2倍にする関数 4 for i in range(len(ls)): 5 ls[i]=2*ls[i] 6 return ls 7 8if twice(a)==[2,4,6]: 9 print("OK") 10 11print("a =",a)

【期待する出力】

OK a = [1,2,3]

【結果】

OK a = [2,4,6]

リストaが2倍になってしまいました。aは[1,2,3]のままでいてほしいのです。後でまた使うので。
確かにif文でtwiceをaに使いました。しかしこれは「仮にaにtwiceを適用したら...」の意味ではないのでしょうか。
実際にはaは2倍にならないという認識でした。どこが間違っているのか教えてください。

②コードが不細工になることを承知でaを別の場所に退避させるようにコードを変えました。

Python

1a = [1,2,3] 2original_a = a #aを別の変数に逃がした 3 4def twice(ls): 5 for i in range(len(ls)): 6 ls[i]=2*ls[i] 7 return ls 8 9if twice(a)==[2,4,6]: 10 print("OK") 11 12a = original_a #上で逃がしたaを呼び戻した 13print("a =",a) 14print("original_a"=original_a)

【結果】

OK a = [2, 4, 6] original_a = [2, 4, 6]

やっぱりaはtwiceされました。なんならoriginal_aも2倍にされました。
どこでoriginal_aにtwiceがかかったのでしょう...?コード内でoriginal_aには何も変更を加えていないはずです。

【教えてほしいことまとめ】
①で、期待する出力を出す方法
②で、original_aが2倍にされた理由

宜しくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

とりあえず回避法から。

新しくリストを作って返す方法

Python

1def twice(ls): 2 ret = [] 3 for e in ls: 4 ret.append(2*e) 5 return ret

新しくリストを作って返す方法(内包表記)

Python

1def twice(ls): 2 return [2*e for e in ls]

リストのコピーを作る方法

Python

1def twice(ls): 2 ret = ls[:] 3 for i in range(len(ret)): 4 ret[i] *= 2 5 return ret

なぜ、元の方法だと上手くいかないか?

Pythonは、変数にオブジェクトの参照値を束縛します。
参照値をコピーしても、参照先は変わりません。よって、要素が共有されます。

参考:Qiita - pythonでのリストの要素の変更とリストのコピー


「仮にaにtwiceを適用したら...」の意味ではないのでしょうか。

仮に、という意味は含まれないですね。
このように、副作用がある(引数に影響を及ぼす)ような関数は慎重に取り扱わねばなりません。

投稿2018/05/26 13:34

編集2018/05/26 13:37
LouiS0616

総合スコア35660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Sigma1630

2018/05/26 14:09

理解しました、ありがとうございます! また参考に頂いたリンクは要勉強項目ですね。浅いコピーとか深いコピーとか、言葉は聞いたことがありますが、実際に書いてみて意味がわかった気がします。
Sigma1630

2018/05/26 14:18

頂いたリンクの浅い・深いのコピーに関して追加で教えていただきたいです。 深いコピーは浅いコピーの上位互換な感じを受けますが、浅いコピーをあえて使う理由はなんですか?
LouiS0616

2018/05/26 14:29 編集

浅いコピーの方が処理が軽く、メモリを圧迫しません。 ですので、深いコピーを要するときを除いては浅いコピーの方が便利なのです。 また、例えばpythonのリストは自分自身を要素として持つことができます。 コピーが延々と循環してしまうため、これの深いコピーを作ることはできません。 (copy.deepcopyは、既にコピーしたオブジェクトを記憶することでこの問題を回避しているようです。)
Sigma1630

2018/05/26 14:30

早急のご回答ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問