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

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

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

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

Q&A

解決済

1回答

284閲覧

python 関数を呼び出した時何故か全く関係ない変数に代入がされる

kakini

総合スコア40

Python

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

0グッド

0クリップ

投稿2022/09/12 07:01

pythonで関数を呼び出した際にメインの流れの中にある変数の内の一つに
何故かその関数の返り値と同じ値が代入されています

プログラムは省略してますが関数の部分は下記になります

python

1def sma_slope_average(df_csv, row_A, row_B, n): 2 sma_slope_list={} #行番号をキーにして行番号直近のn個の角度を保存。ロング・ショート両方の行を保存 3 #ゴールデンクロス(ロング)行のn個の角度 4 for row in row_A: 5 for x in range(1,n+1): 6 y = (df_csv["sma01_A"][abs(row)] - df_csv["sma01_A"][abs(row)-x])*100 7 tan = y / x 8 if x == 1: 9 sma_slope_list[row] = [math.degrees(math.atan(tan))] 10 else: 11 sma_slope_list[row].append(math.degrees(math.atan(tan))) 12 13 #デッドクロス(ショート)行のn個の角度 14 for row in row_B: 15 for x in range(1,n+1): 16 y = (df_csv["sma01_B"][abs(row)] - df_csv["sma01_B"][abs(row)-x])*100 17 tan = y / x 18 if x == 1: 19 sma_slope_list[row] = [math.degrees(math.atan(tan))] 20 else: 21 sma_slope_list[row].append(math.degrees(math.atan(tan))) 22 23 24 #上記で求めた各行のn個の角度の平均を求めて辞書に行番号と共に入れる 25 sma_slope_average_list = {} 26 for row, value in sma_slope_list.items(): 27 sma_slope_average_list[row] = [sum(value) / len(value)] 28 29 return sma_slope_average_list 30 31 32#2本の移動平均線の交点付近の時間(行)から上位の時間足(ここでは日足)の直近n個の角度の平均を求める 33#※この関数はsma_slope_average関数から返り値を貰った変数を参照にしているので先にsma_slope_average関数を使う事 34#※上位時間足は日足を使う事を前提に作ってあるので日足以外で使う場合は関数を書き換える必要あり 35def sma_average_add_daily(df_csv, df_joui, sma_slope_list, n): 36 sma_slope_average_daily_list={} #キーに移動平均の交点行、1番目の値に元の移動平均線の平均角度、2番目の値に上位時間足の角度の平均 37 for row, value in sma_slope_list.items(): 38 date = str(df_csv["日時"][abs(row)]).split()[0] #交点行の時間を求める 39 if date[5:] == "01-01": #交点行が1月1日ならポジションを取らない 40 continue 41 date_time = dt.datetime.strptime(date, '%Y-%m-%d') #datetime型に変換 42 43 if date_time.date().strftime("%A") == "Saturday": #交点行が土曜日の場合は上位の時間足の行を1引く。それ以外は普通に参照 44 date_time = date_time + dt.timedelta(days=-1) 45 daily_index = df_joui.index[(df_joui["日時"] == str(date_time.date()))] 46 else: 47 daily_index = df_joui.index[(df_joui["日時"] == str(date_time.date()))] 48 49 50 51 #上位の時間足の角度の平均を求める 52 sma_daily=0 53 try: 54 for x in range(1, n): 55 #print(daily_index) 56 y = (df_joui["sma01_B"][daily_index[0]] - df_joui["sma01_B"][daily_index[0]-x]) * 100 57 #print(y) 58 tan = y / x 59 sma_daily += math.degrees(math.atan(tan)) 60 sma_daily /= n 61 sma_slope_average_daily_list[row] = value #1番目に元の移動平均線の平均角度を入れる 62 sma_slope_average_daily_list[row].append(sma_daily) #2番目に上位時間足の移動平均線の平均角度を入れる 63 except: 64 print("エラー:", row, "行目", df_csv["日時"][abs(row)]) 65 continue 66 67 sma = sma_slope_average_daily_list 68 return sma

この関数をメインの流れの時に↓の様に続けて実行します
sma_slope = sma_slope_average(df_csv, row_A, row_B, 5)
sma_slope2 = sma_average_add_daily(df_csv, df_joui, sma_slope, 5)

そうすると何故か2行目のsma_average_add_daily関数を実行した時
sma_slope2だけでなく1行目のsma_slopeに全く同じ返り値が代入されています
sma_average_add_daily関数を見直してみてもsma_slopeに対して何かをするコードは見当たりません
何故こんな事が起こるのでしょうか?


引数は
・df_csv:pandasのデータフレーム
・df_joui:pandasのデータフレーム
・row_A:int型の数字
・row_B:int型の数字

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

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

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

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

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

kakini

2022/09/12 07:08

訂正:引数の部分 row_A:int型の数字が複数入ったリスト row_B:int型の数字が複数入ったリスト
can110

2022/09/12 07:16

状況としては以下の1と2のprint結果が異なってしまい、3と同じになる、という感じでしょうか? sma_slope = sma_slope_average(df_csv, row_A, row_B, 5) print(sma_slope) # 1 sma_slope2 = sma_average_add_daily(df_csv, df_joui, sma_slope, 5) print(sma_slope) # 2 print(sma_slope2)# 3
kakini

2022/09/12 07:19

はいその通りです 1の時点ではsma_slopeは正常ですが 2をの時点では3と同じになっています
can110

2022/09/12 07:33 編集

実行環境、手順についても記載すると何か手掛かりになるかもしれません。 Jupyter上だと一部のセル値が更新されていないなどで意図しない結果になる可能性もあるので。 また、可能であれば再現可能なdfデータと最小限で実行可能な完全なコードを提示すると回答得られやすくなります。 あ。辞書の値が元の値を参照しているみたいですね。
kakini

2022/09/12 07:38

ご指摘ありがとうございます。 これから出かけなければならないので後日詳細を書いた質問を 投稿しなおしてみます
guest

回答1

0

ベストアンサー

Python

1 sma_slope_average_daily_list[row] = value #1番目に元の移動平均線の平均角度を入れる 2 sma_slope_average_daily_list[row].append(sma_daily) #2番目に上位時間足の移動平均線の平均角度を入れる

においてvalueは関数の引数として渡された辞書の値(リスト)であり
それがそのまま代入されているので、元のリストを指しています。
それにappendしているので元のリストも変わります。
単純化すると以下のような動きになっています。
回避するには、リストをコピーした結果を代入するとよいでしょう。

Python

1def func1(): 2 return {'a':[1,2], 'b':[3,4]} 3 4def func2(dic1): 5 dic2 = {} 6 for row, value in dic1.items(): 7 dic2[row] = value # 元のリストと同じモノを指している! 8 dic2[row].append(9)# 元のリストが更新される! 9 10 return dic2 11 12dic1 = func1() 13print(dic1) # {'a': [1, 2], 'b': [3, 4]} 14dic2 = func2(dic1) 15print(dic1) # {'a': [1, 2, 9], 'b': [3, 4, 9]} 16print(dic2) # {'a': [1, 2, 9], 'b': [3, 4, 9]}

投稿2022/09/12 07:42

can110

総合スコア38262

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

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

kakini

2022/09/13 03:58

ありがとうございます 回答を参考にして自分でも少し調べてみましたが a=[1,2,3] b=a 上記の様にリスト等のオブジェクトを代入する時、データが保管されている「元となる場所」の住所のみを 代入するからbのリストの内容を変更したり、追加したりしてもbだけじゃなくaも値が変わってくるんですね 初めて知りました てっきりb=aで新しい変数にaの内容をコピーしていれた「別の物」になると思ってましたので bの内容を変えても問題無いと思っていました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問