[解決済み] python pandas dataframe, pass-by-value or pass-by-reference?
質問
関数にデータフレームを渡し、関数内で修正する場合、値渡しなのか、参照渡しなのか、どちらでしょうか?
次のコードを実行します。
a = pd.DataFrame({'a':[1,2], 'b':[3,4]})
def letgo(df):
df = df.drop('b',axis=1)
letgo(a)
の値は
a
の値は関数呼び出しの後でも変わりません。パスバイバリューということでしょうか?
また、以下を試してみました。
xx = np.array([[1,2], [3,4]])
def letgo2(x):
x[1,1] = 100
def letgo3(x):
x = np.array([[3,3],[3,3]])
その結果
letgo2()
は変更されます。
xx
と
letgo3()
がない。なぜこのようになるのでしょうか?
どのように解決するのですか?
簡単に言うと、Pythonは常に値渡しですが、Pythonの変数はすべて実際にはあるオブジェクトへのポインタなので、時々参照渡しのように見えることがあります。
Pythonではすべてのオブジェクトはmutableかnon-mutableのどちらかです。例えば、リスト、ディクショナリー、モジュール、Pandasデータフレームはmutableで、ints、string、tupleはnon-mutableです。Mutableなオブジェクトは内部で変更することができますが(例えば、リストに要素を追加する)、Non-Mutableなオブジェクトは変更することができません。
冒頭で述べたように、Pythonの変数はすべてオブジェクトへのポインタと考えることができます。変数を関数に渡すと、関数内の変数(ポインタ)は常に渡された変数(ポインタ)のコピーになります。つまり、内部変数に何か新しいものを代入しても、やっていることはローカル変数が別のオブジェクトを指すように変更するだけです。これは、変数が指していた元のオブジェクトを変更(変異)するわけではなく、外部変数が新しいオブジェクトを指すようになるわけでもありません。この時点では、外部変数はまだ元のオブジェクトを指していますが、内部変数は新しいオブジェクトを指しているのです。
元のオブジェクトを変更したい場合(Mutableデータ型でのみ可能)、オブジェクトを変更するようなことをしなければなりません。
を使わずに
でオブジェクトを変更するようなことをしなければなりません。このため
letgo()
と
letgo3()
は外部項目を変更しないままですが
letgo2()
はそれを変更します。
ursan が指摘するように、もし
letgo()
がこのようなものを使っていた場合、元のオブジェクトを変更(変異)してしまい
df
が指す元のオブジェクトを変更(変異)し、 それによってグローバルな
a
変数で見られる値を変更することになります。
def letgo(df):
df.drop('b', axis=1, inplace=True)
a = pd.DataFrame({'a':[1,2], 'b':[3,4]})
letgo(a) # will alter a
場合によっては、実際に直接代入を行わなくても、元の変数を完全にくりぬいて、新しいデータで埋め合わせることができます。
v
が指す元のオブジェクトを変更し、それによって
v
を使用したときに表示されるデータが変わります。
def letgo3(x):
x[:] = np.array([[3,3],[3,3]])
v = np.empty((2, 2))
letgo3(v) # will alter v
に直接何かを代入していないことに注意してください。
x
の内部範囲全体に何かを割り当てていることに注意してください。
x
.
どうしても完全に新しいオブジェクトを作成して外部から見えるようにしなければならない場合(pandasで時々あることです)、2つのオプションがあります。クリーン」なオプションは、例えば新しいオブジェクトを返すだけです。
def letgo(df):
df = df.drop('b',axis=1)
return df
a = pd.DataFrame({'a':[1,2], 'b':[3,4]})
a = letgo(a)
もう一つの方法は、関数の外に出て、グローバル変数を直接変更することです。これは
a
を新しいオブジェクトに変更し、そのオブジェクトを参照するすべての関数は
a
を参照するすべての関数はその新しいオブジェクトを見ることになります。
def letgo():
global a
a = a.drop('b',axis=1)
a = pd.DataFrame({'a':[1,2], 'b':[3,4]})
letgo() # will alter a!
グローバル変数を直接変更することは、通常は悪い考えです。なぜなら、あなたのコードを読む人は、どのように
a
がどのように変更されたかを理解するのが難しいからです。(私は一般的に、スクリプト内の多くの関数で使用される共有パラメータにグローバル変数を使用しますが、それらのグローバル変数を変更させないようにします)。
関連
-
[解決済み] PandasでDataFrameの行を反復処理する方法
-
[解決済み] 変数を参照渡しする方法を教えてください。
-
[解決済み] 列の値に基づいてDataFrameから行を選択するにはどうすればよいですか?
-
[解決済み] Pandasのカラム名のリネーム
-
[解決済み] Pandas DataFrameからカラムを削除する
-
[解決済み】ネストされたディレクトリを安全に作成するには?
-
[解決済み】Pythonに三項条件演算子はありますか?
-
[解決済み] PythonでのAWS Lambdaのインポートモジュールエラー
-
[解決済み] django.db.migrations.exceptions.InconsistentMigrationHistory
-
[解決済み] 新しいpip backtrackingの実行時問題の解決
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] 変数を参照渡しする方法を教えてください。
-
[解決済み] DataFrameの文字列、dtypeがobjectの場合
-
[解決済み] pandasのDataFrameから空のセルを含む行を削除する
-
[解決済み] 小数点以下1桁を取得する[重複]。
-
[解決済み] DataFrameに日付間の日数カラムを追加する pandas
-
[解決済み] ファブリック経由でデプロイユーザとしてvirtualenvを有効化する
-
[解決済み] 値で列挙名を取得する [重複]。
-
[解決済み] python-requests モジュールからのすべてのリクエストをログに記録します。
-
[解決済み] subprocess.run()の出力を抑制またはキャプチャするには?
-
[解決済み] Pythonの辞書にあるスレッドセーフについて