🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

3回答

5312閲覧

defとListの関係について

Poohtaro

総合スコア8

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/03/21 08:58

前提・実現したいこと

Python初心者です。的外れなことを聞いていたら申し訳ないです。

Pythonで関数を呼び出し引数をListに入れ、そのListを戻り値として変数に代入したのちに違う引数で同じようなことをするコードを書こうと思いました。
今回の場合は引数を1,2,3としてAに、4,5,6をBに代入します。

発生している問題・エラーメッセージ

望む結果としてはprint(A)が[1,2,3]、print(B)が[4,5,6]ですが実際に出てきたのは
print(A)print(B)ともに[4,5,6]でした。なぜこうなってしますのかがわかりません。

該当のソースコード

Python

1list_x = [] 2 3 4def list_in(num1, num2, num3): 5 list_x.clear() 6 list_x.append(num1) 7 list_x.append(num2) 8 list_x.append(num3) 9 return list_x 10 11 12A = list_in(1, 2, 3) 13B = list_in(4, 5, 6) 14 15print(A) 16print(B)

###結果

[4, 5, 6] [4, 5, 6]

試したこと

return list_x

C=list_x return C

結果は同じでした。
PyCharmのデバックモードで調べてみたところ、B=list_in(4,5,6)の処理が終わるとAが[4,5,6]に変わりました。
自分でGoogle先生にも聞いてみましたが、検索窓に何を入れて検索すれば自分の欲しい情報が手にはいるのかわかりませんでした。

補足情報(FW/ツールのバージョンなど)

Python3.8.5
PyCharm
windows10

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

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

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

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

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

guest

回答3

0

ベストアンサー

これは、pythonのはまりどころでもあるし、勘所でもあります。まず何が起きているか説明してみます。

まずは以下のコードの動作は把握されていますか?

python

1list_x = [1, 2, 3] 2 3A = list_x 4B = list_x 5 6print(A) 7# [1, 2, 3] と表示 8print(B) 9# [1, 2, 3] と表示 10 11list_x[0] = 10 12 13print(A) 14# [10, 2, 3] と表示 15print(B) 16# [10, 2, 3] と表示 17

このように、list_x、A、B はすべて「同じリストを指して」います。 pythonで「A = list_x」のような記述をすると、Aはlist_xと同じものを指すようになるのです。

また、ここで扱われている、1つしかない「リスト」は、 「list_x = [1, 2, 3]」の部分で生成されています。

さて、問題のコードを関数を使わずに書くと以下のようになります。

python

1 2list_x = [] 3 4# A = list_in(1, 2, 3) 5list_x.clear() 6list_x.append(1) 7list_x.append(2) 8list_x.append(3) 9A = list_x 10 11#B = list_in(4, 5, 6) 12list_x.clear() 13list_x.append(4) 14list_x.append(5) 15list_x.append(6) 16B = list_x 17 18print(A) 19print(B) 20

ここでも同様に、1つしか作られていないリストをlist_x、 A、Bで共有していることがわかります。

どのようにすれば望みの結果になるかについてですが、

python

1def list_in(num1, num2, num3): 2 list_x.clear() 3 list_x.append(num1) 4 list_x.append(num2) 5 list_x.append(num3) 6 return list_x

この関数は、「この関数の外で定義されているlist_xの内容を空にし、引数の数を設定して返す」という関数になっていますので、そもそも当初の目的に合っていないと思います。 また、このように、実行することで「副作用 (引数に関係の無い値を変更してしまうこと)」を起こすような関数は使わない流れになってきているので、これをベースに考えないほうがいいでしょう。

「新しいリストを作って、引数の値を設定して返す」関数にするのはいいのではないでしょうか。
既存の書き方に寄せるとこんな感じです。

python

1def list_in(num1, num2, num3): 2 list_new = [] 3 list_new.append(num1) 4 list_new.append(num2) 5 list_new.append(num3) 6 return list_new

この場合、list_xは使いませんが。


コメントへの補足で追記します。

「A,B がlist_xを参照している」のではないことは、以下のコードで確認できます。

python

1list_x = [1, 2, 3] # 1 2 3A = list_x 4B = list_x 5 6print(A) 7# [1, 2, 3] と表示 8print(B) 9# [1, 2, 3] と表示 10 11list_x = [10, 20, 30] # ★ 12 13print(A) 14# [1, 2, 3] と表示 15print(B) 16# [1, 2, 3] と表示

★のところで、list_xは「新しく作られたリスト」を参照するように変えられましたが、A, Bはlist_xではなく、もとの 1 で作られたリストを参照しているので値は変りません。

投稿2021/03/21 09:42

編集2021/03/21 10:17
TakaiY

総合スコア13754

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

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

Poohtaro

2021/03/21 09:54

回答ありがとうございます。 最初のコードの動作は理解しています。 今回の場合だとA=list_xかつB=list_xのためlist_x=[4,5,6]となったときにAもlist_xに合わせて変わったということですね。つまりAが[1,2,3]という値を保持しているわけではないということですね。
Poohtaro

2021/03/21 10:03

「最初のコードの動作は理解しています。」と書きましたが、よく見たら理解していませんでした。 これまでの自分ならlist_x[0]=10の後にA=list_x,B=list_xと書いていたでしょうがその必要はないんですね。 やはりA,Bがlist_xを参照しているため、list_xが変化するとA,Bともに変化するんですね。
TakaiY

2021/03/21 10:03

AとBが(list_xもですが)が同じものを持っている、というのが近いですね。 そして、「持っている』という意識は捨てて、指している(参照している)というイメージを掴むのが大事だと思います。
TakaiY

2021/03/21 10:11

1つ前のリコメントへのコメントでした。 「A,Bがlist_xを参照している」これももう一歩です。 「A, B, liste_xが同じリストを参照している」です。これは、「たとえ list_x という変数を消すことができたとしても、A、 Bはそのリストを参照している」ということです。 そして、そのリストは、参照している変数が無くなったら捨てられ(ガベコレされ)ます。というのは先の話ですね。
Poohtaro

2021/03/21 10:25 編集

今回の問題では、自分の変数の考え方が間違っていたんですね。 ここまでの解説ありがとうございました。とても分かりやすかったです。
guest

0

関数呼び出しの問題ではありません。
リストの性質です。

list_x、A、Bというのは変数であってリストそのものではありません。
list_inという関数は2回呼びされていますが、そのときに同じlist_xの中身であるリストを返しています。
2回目に呼ばれたときは、list_xの中身を書き換えています。それはAに代入されたリストですので、Aをprintすると書き換えられた中身が印字されます。

これを防ぎたければ、list_xをlist_inの中で作るとか、return文でコピーを作って返す、などの方法があります。

以下を見て考えてみてください。

python

1>>> A = [1] 2>>> B = A 3>>> B.clear() 4>>> B.append(4) 5>>> print(A) 6[4]

これと同じようなことが起きています。

投稿2021/03/21 09:24

ppaul

総合スコア24670

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

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

Poohtaro

2021/03/21 09:35

回答ありがとうございます。 1行目のList_x=[]をdef list_in(num1,num2,num3):の次の行に持ってくることで無事解決できました。 変数は参照しているだけで、値を保持しているわけではないということですかね? まだ理解が追い付いていませんが、もう少し自分で調べてみようと思います。
guest

0

グローバル変数list_xに上書きしていってるだけですね。
後で実行した方の数値になってしまいます

関数の結果をコピーしたものを代入するようにしましょう

投稿2021/03/21 09:01

編集2021/03/21 09:03
y_waiwai

総合スコア88038

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

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

Poohtaro

2021/03/21 09:30

回答ありがとうございます。 1行目のList_x=[]をdef list_in(num1,num2,num3):の次の行に持ってくることで無事解決できました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問