1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pythonの誤解

Posted at

Pythonに見られる誤解について説明します。

誤解1:イミュータブルに代入すると「イミュータブルだから新しいオブジェクトが作られる」

X = 1
X = 2

よくある誤解

①で X に 1 が代入される。
②で「1 を 2 に変更しようとする」が、1 はイミュータブルなので変更できない。
だから X には新しい 2 が作られて代入される。

正しい理解

Python の = は「代入」というより 束縛(名前付け) を行う。

  • X = 1 は「Xの中身を1に書き換える」ではなく、
    「名前 X が、整数オブジェクト 1 を参照するようにする」
  • X = 2 は、
    「名前 X が、整数オブジェクト 2 を参照するように結び直す(再束縛する)」

つまりこの2行は、オブジェクト1を2に変更しているのではなく
Xの参照先を 1 から 2 に付け替えているだけ

補足:イミュータブルが問題になるのは「オブジェクトそのものを変更しようとしたとき」であって、= による束縛の付け替えとは別の話。

誤解が起きる原因の考察

X = 1 を「Xに1という値が入る」と教えられると、学習者は Xそのものが1になる(Xは1である) という認識になりやすい。

その結果、X = 2 を見たときに

  • 「Xの中に入っている 1 を 2 に変える処理」
  • 「1 を 2 に変更する(書き換える)処理」

だと誤解してしまう。

しかし実際には、= は「中身の書き換え」ではなく 名前の束縛(参照先の付け替え) であり、
X = 2Xが参照するオブジェクトを 1 から 2 に切り替える(再束縛する) だけである。

誤解2:関数引数がイミュータブルだと「値渡し」、ミュータブルだと「参照渡し」

よくある誤解

  • イミュータブル(int, str, tuple など)を渡すと「値渡し」
  • ミュータブル(list, dict, set など)を渡すと「参照渡し」

正しい理解

Pythonの関数呼び出しは一貫して 「オブジェクト参照(への束縛)を渡す」 方式。

  • 呼び出し時に、引数名(仮引数)は渡されたオブジェクトへ束縛される
  • そしてこの 引数名(仮引数)は、関数のローカル変数 である
    → 関数の外側の変数名とは別物(同名でも別スコープ)

よく使われる表現としては、次のどちらかが近いです:

  • call by sharing(共有による呼び出し)
  • call by object reference(オブジェクト参照渡し)

じゃあなぜ「イミュータブル=値渡し」に見えるの?

イミュータブルは 関数内で“中身を変更する”ことができない ので、結果として

  • 関数内で代入(再束縛)しても
  • 影響するのは ローカル変数である仮引数 だけ
  • 呼び出し元の変数は変わらない

→ これが「値がコピーされた」ように見える原因。

例:イミュータブル(int)

def f(x):
    x = x + 1  # x(ローカル変数)を別の int オブジェクトへ再束縛しているだけ

a = 10
f(a)
print(a)  # 10 のまま

なぜ「ミュータブル=参照渡し」に見えるのか

ミュータブル(list / dict など)は 同じオブジェクトの中身を変更できる ため、関数内で破壊的操作をすると、呼び出し元も「同じオブジェクト」を見ているので状態の変化がそのまま観測されます。

def g(xs):
    xs.append(99)  # 同じ list オブジェクトの中身を変更

b = [1, 2]
g(b)
print(b)  # [1, 2, 99]

誤解3:+= は常に「新しいオブジェクトを作る」

型によって挙動が違う

  • イミュータブルint, str, tuple など)
    → だいたい 新規生成&再束縛
  • ミュータブルlist など)
    破壊的に変更 することがある

例1:イミュータブル(int

a = 1
b = a
a += 1         # 新しい int が作られ、a が再束縛される
print(a)       # 2
print(b)       # 1(bは変わらない)

例2:イミュータブル(str)

s = "a"
t = s
s += "b"       # 新しい str が作られ、s が再束縛される
print(s)       # "ab"
print(t)       # "a"(tは変わらない)

例3:ミュータブル(list)

a = [1, 2]
b = a
a += [3]       # aの中身が変わる(結果としてbも変わる)
print(a)       # [1, 2, 3]
print(b)       # [1, 2, 3]

まとめ

Pythonでは「変数=箱」ではなく「名前→オブジェクトへの参照」と考える。
Pythonによくみられる誤解について説明しました。

1
2
1

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
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?