「Pythonでは、代入するときはすべて参照渡しだ」と本に書いてあったのですが、イミュータブルなオブジェクトは代入するときに値渡しですよね。
では、本に書いてあった「Pythonでは、代入するときはすべて参照渡しだ」という記述は嘘ですよね。
多くのサイトで、「Pythonでは、代入するときはすべて参照渡しだ」と書いてあるのですが、なぜそうではないのにそんなことを書いているのですか。なにか意図があったりするのでしょうか...
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
「~渡し」は関数呼び出しの際の言葉なので、そもそも適切な語の使用ではありませんがそれはともかく。
代入だろうと関数呼び出しだろうと、すべて参照です。
python
1>>> i = 1 2>>> id(i) 39169088 4>>> j = i 5>>> id(j) 69169088 7>>> def f(x): 8... print(id(x)) 9... 10>>> f(i) 119169088
id
関数については以下を参照。
2. 組み込み関数 — Python 3.6.5 ドキュメント | id
イミュータブルなオブジェクトは代入するときに値渡しですよね。
そういう仕様はpythonにはありません。immutableだからといって、mutableなオブジェクトと扱いが区別される訳ではありません。
JavaやPHPなどプリミティブ型と参照型で扱いを変える言語があるので、もしかしたらそれらと混同しているのかもしれませんが、pythonの仕様をプリミティブ型と参照型という用語で説明するなら「すべて参照型で、プリミティブ型は存在しない」ということになります。
たしかに値渡しかな? と思うこともあります。
python
1>>> def f(x): 2... x = x + 1 3... 4>>> a = 10 5>>> f(a) 6>>> a 710
これをちゃんと説明しようとすると長くなるので大まかな流れだけ説明すると、pythonの足し算は、通常左側のオブジェクトの__add__
メソッドが呼ばれる仕組みになっています。x + 1
はx.__add__(1)
として扱われます。__add__
がオブジェクト自身を書き換えるように実装することも不可能ではありませんが(mutableなオブジェクトなら)、通常は結果を表す新たなオブジェクトを返すようになっています。その結果のオブジェクトをローカル変数のx
に束縛する……というのがf
の中のx = x + 1
の挙動です。この処理は呼び出し時の実引数(オブジェクトa
ないし10
)には何ら影響を及ぼさないことがわかるかと思います。
投稿2019/02/12 09:58
編集2019/02/12 11:04総合スコア30933
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/02/12 10:19
2019/02/12 11:06 編集
2019/02/12 16:44 編集
2019/02/12 14:04
2019/02/12 15:38 編集
2019/02/12 16:34
0
ベストアンサー
「Pythonでは、代入するときはすべて参照渡しだ」
厳密に言えば、参照の値渡しです。「変数としては別だけどオブジェクトは共通」というものです。
イミュータブルなオブジェクトは代入するときに値渡し
そうかも知れませんが、それは実装の最適化でたまたまそうなっているだけ、とも解釈できます。
イミュータブルなオブジェクトであれば、参照を渡そうが値として渡そうが、どちらにしても破壊的変更は不可能なので、Pythonコード上からはどちらでも動作に差はありません。
投稿2019/02/12 09:52
総合スコア145183
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/02/12 13:03
2019/02/12 14:12 編集
2019/02/12 14:34 編集
0
immutable なオブジェクトは変更しようとしたタイミングで別オブジェクトとして複製されるコピーオンライト戦略をとっています。
Wikipediaより引用
複製を要求されても、コピーをした振りをして、とりあえず原本をそのまま参照させるが、ただし、そのままで本当に書き換えてはまずい。原本またはコピーのどちらかを書き換えようとしたときに、それを検出し、その時点ではじめて新たな空き領域を探して割り当て、コピーを実行する。これが「書き換え時にコピーする」、すなわちコピーオンライト (Copy-On-Write) の基本的な形態である。
実際、以下のようにこの挙動を確認できます。
id() でオブジェクトの識別子が取得できるので(Cでいうオブジェクトのアドレスと思えばよい)
これで確認してみると、
python
1a = 1 # int は immutable 2print(id(a)) # 9145152 3b = a 4print(id(b)) # 9145152 この時点で a と指す実態は同じ 5b = 2 # immutable なオブジェクトを変更しようとすると.... 6print(id(b)) # 9145184 a とは別のオブジェクトとなる
変更するまでは a と b のオブジェクトは同じであることがわかります。
投稿2019/02/12 10:04
編集2019/02/12 10:30総合スコア21956
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/02/12 10:12 編集
2019/02/12 10:31
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。