7
7

More than 1 year has passed since last update.

pythonのポインタ渡しを理解する話

Last updated at Posted at 2021-10-06

TL;DR

代入をするときポインタが渡される
constな値を代入した際にもその値のポインタが渡される

Pythonでもある意味厄介なポインタ

C言語にもあるポインタの概念、こいつの仕様を理解しようと色々悪戦苦闘したのはなつかしいです(今でも理解できていない節がありますが)。その後Pythonでもポインタを使いたいと思い調べたら言語特有の省略主義的なものゆえか頭が完全にバグったのでまとめておきたいと思います。
(上記の通りポインタに対して完全な理解をしたわけではないので終始誤っていることを記述する可能性がありますが、ご了承ください。また以下のコードはすべてインタプリンタ上で動かしています)

実行環境 

python: Python 3.9.0
OS: Windows 10

変数同士の代入

a=3
id(a) #1392940902768
b=9
id(b) #1392940902960
b=a
id(b) #1392940902768

id関数は引数のアドレスを返してくれます。上記のような単純な代入ではそこいらでも言われている通りちゃんとポインタ渡しになっています。

値の代入

続き
a=7
print(b) #9
id(a) #1392940902896

おかしくなっていくのはその後です。変数a,bは同じアドレスを共有しているので当然aに値を代入されれば同じようにしてbにも反映されるはずです。
ですが実際はそうはならず、さらにaのアドレスが変わってしまいました。C言語で似たようなことをすればそうはならないので混乱してしまいました。ただその後にふと確かめてみたことがあります。

値のアドレス

続き
id(7) #1392940902896

どうやら値自身にもアドレスが設定されているようです、constな変数ということでしょうか。
このことからpythonにはそもそも値渡しが存在しない、もしくは明記しないといけないのではないか?という可能性に至りました。

constなintのアドレスを検証
for i in range(20):
  print(i,end=":")
  print(id(i)-id(0))
結果
0:0
1:32
2:64
3:96
4:128
5:160
6:192
7:224
8:256
9:288
10:320
11:352
12:384
13:416
14:448
15:480
16:512
17:544
18:576
19:608

値にはそれぞれアドレスが設定されており、一定の周期性を持つことがわかります。
よって前処理の段階であらかじめアドレスが設定されていることがわかります。

listで回避してみる

a=[1,2,3]
id(a) #2960827260992
b=a
id(b) #2960827260992
a[0]=9
b #[9,2,3]
id(a) #2960827260992

このようにすればC言語みたいなポインタの使い方ができます。(任意のアドレス上にあるオブジェクトに格納されているオブジェクトのアドレスを変更しているということになるのでしょうか)
ただlistを前提とした運用ならともかく、上記のようにintで収まる範囲ならかなり違和感を覚えます。(もっといい書き方があると思いたい)

値渡しをしてみる

import copy
a=3
id(a) #1392940902768
b=copy.deepcopy(a)
id(a) #1392940902768
id(b) #1392940902768

だめでした。(一つの変数が二つのアドレスを持つことになるので当然といえば当然ですが)

toDO

・pythonリファレンスを確認する

確認しました。その結果上記のことは実装に依存する、というとんでもないことが書かれていたので後日追加の 検証をしてみたいと思います。探してくれた友人に感謝を。

7
7
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7