LoginSignup
4
3

More than 3 years have passed since last update.

Pythonの変数はイミュータブルなのでポインタみたくはできない

Last updated at Posted at 2019-02-05

はじめに

C - Not so Diverseを解いている際に引っかかった初歩的なことついてメモとして残しておきます。
結論を先にいうと、Pythonのint型はイミュータブルな型なのでメモリの節約はできません。
[追記2019/2/7]構造体を使えば同じ領域を参照することは出来る。とご指摘いただきました。ありがとうございます。

ポインタ渡し

もともとやりたかったことはこんな感じ。

sorce.c
#include <stdio.h>

void plus();

int main(void){
    int num2 = 5;
    plus(&num2);
    printf("%d \n",num2);
    return 0;
}

void plus(int *x){
    *x += 2;
}
>>>7

Pythonで値を保持し続ける

そして、Pythonでポインタ渡しと同じことをしようと試みるも...

sorce.py
def main():
    num2 = 5
    plus(num2)
    print(num2)

def plus(num2):
    num2 += 2
    return num2

if __name__=="__main__":
        main()
>>>5

となってしまいます。plus()を受け取れていないからですね。Cに慣れているとやりがちでしょうか。
正しくはnum2 = plus(num2)としてnum2を出力すれば良い。

def main():
    num2 = 5
    num2 = plus(num2)
    print(num2)

def plus(num2):
    num2 += 2
    return num2

if __name__=="__main__":
        main()
>>>7

これでひとまず値が保存されているので、良さそう。

ポインタ渡しになっていない

メモリの節約を試みたいので以下のようにしてみます。

sorce2.py
num2 = 0
def main():
    global num2
    num2 = 5
    plus()
    print(num2)

def plus():
    global num2
    num2 += 2


if __name__=="__main__":
        main()
>>>7

たとえmain関数であってもglobal宣言はマストです。

sorce2.py↑でポインタ渡しになっているかしらべてみます。

sorce3.py
num2 = 0
def main():
    global num2
    print(id(num2))
    num2 = 5
    print(id(num2))
    plus()
    print(id(num2))
    print(num2)

def plus():
    global num2
    num2 += 2

if __name__=="__main__":
    main()
>>>4393719184
>>>4393719344
>>>4393719408
>>>7

この通り、識別値が変わってしまっています。
Pythonの値渡しと参照渡しによると

渡された値を変更した際に元の値自体も変更されてしまうかどうかは,オブジェクトの型に依存します.
変更不可(Immutable)な型
int, float, str, tuple, bytes, frozenset 等
変更可能(Mutable)な型
list, dict, set, bytearray 等
変更可能な型では,渡された値が変更されると元の値も変更されてしまいます.(新しく領域が確保されません)

ということなので、ダメです!デキマセン!!
イミュータブルな型では別領域が確保されてしまいます。

引数にglobal変数を入れてはいけない

argument.py
num2 = 0
def main():

    num2 = 5
    num2 = plus()
    print(num2)

def plus(num2):
    global num2
    num2 += 2
    return num2

if __name__=="__main__":
    main()
>>>  global num2
     ^
SyntaxError: name 'num2' is parameter and global

引数 and global変数にしているよ〜と怒られます。global変数として使いたいのにglobal変数として宣言しているところを指摘されると混乱しがちですが、plus(num2)の方が上に書いているため当然といえば当然。

おわりに

わざわざ同じ領域を使い続けなくても数字は受け渡し続けられるので値を更新するだけでよさそう。

4
3
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
4
3