Python オブジェクト指向入門【変数とオブジェクトの関係】

Python
この記事は約13分で読めます。

こんにちは、ナナです。

Pythonは「オブジェクト指向言語」と呼ばれる種類のプログラミング言語に含まれます。

この「オブジェクト指向」という考え方は、プログラミング初心者の方にはなかなか理解しづらいのですが、Pythonのプログラムを使いこなすためには乗り越えなければなりません。

まずは、「オブジェクト」というものと「変数」との関係性を理解しましょう。

本記事では次の疑問点を解消する内容となっています。

本記事で学習できること
  • Pythonで管理するオブジェクトとは?
  • オブジェクトIDの役割とは?
  • 他の言語とPythonの「変数」の役割の違いとは?
  • Pythonにおける変数への代入の本当の意味とは?
  • 実例プログラムにおけるオブジェクトの生成から参照までの流れとは?
  • C言語技術者が知るべきPythonとの違いとは?

では、「変数」と「オブジェクト」の関係性について学んでいきましょう。

スポンサー

Pythonの『オブジェクト』と『オブジェクトID』の関係

師匠!Pythonは情報を『オブジェクト』で管理しているってどういうことなんですか?C言語には『オブジェクト』ってないですよね?

『オブジェクト』っていうのが何なのか、よくわかりません。

ナナ
ナナ

Pythonでプログラムをしていくためには、この『オブジェクト』というものへの理解が欠かせません。

C言語にはない『オブジェクト』の考え方を学んでいきましょう。

実は、ここまでカリキュラムを進めてきた皆さんは『オブジェクト』というものにすでに触れています。改めて『オブジェクト』が何なのかを理解していきましょう。

Pythonで管理される『オブジェクト』とは?

Pythonでは「数」「文字列」「リスト」「タプル」といったあらゆる情報が『オブジェクト』として管理されています。

つまり、次のような情報は全て『オブジェクト』として管理されているということです。

10              # 整数値
3.14            # 浮動小数点数
"Hello"         # 文字列
[10, 20, 30]    # リスト
(40, 50, 60)    # タプル
オブジェクトの種類

このようにPythonという言語では、様々な情報は『オブジェクト』という枠組みの中で管理されているのです。

ナナ
ナナ

「数」や「文字列」もオブジェクトなんです。つまり、今まで皆さんはプログラムの中で『オブジェクト』をたくさん使ってきたということですね。

『オブジェクト』に紐づく『オブジェクトID』とは

プログラムが動く中で『オブジェクト』は大量に生成されることになります。そのオブジェクトを適切に扱うためには、オブジェクトを識別できる仕組みが必要となります。

それが、『オブジェクトID』と呼ばれる識別子です。

『オブジェクトID』は、「id関数」を使うことで取得することができます。

書式
 id(オブジェクト

使用例
 id(1)
 id(”Hello”)

意味
 指定したオブジェクトのオブジェクトIDを取得する。

実際にプログラムから使用してみましょう。print関数と組み合わせて画面に『オブジェクトID』を表示してみます。

print(id(10))
print(id(3.14))
print(id("Hello"))
print(id([10, 20, 30]))
print(id((40, 50, 60)))

実行結果は次のように、オブジェクト毎に異なる『オブジェクトID』が付与されているのがわかりますね。

140720290641008
2705538589368
2705548071856
2705547616776
2705551508824
オブジェクトに紐づくID

ものすごく大きな数字が紐づいていますが、これが『オブジェクトID』です。

ナナ
ナナ

プログラムを動かす度にIDは変わります。皆さんの環境では違う数字が表示されることでしょう。

スポンサー

「変数」と「オブジェクト」の関係性

「10」みたいな数も『オブジェクト』とは。わたしは知らず知らずのうちにオブジェクト使ってたんですね。

「変数」に「10」を代入するってことは、「変数」に「オブジェクト」を入れるってことなんですね!

ナナ
ナナ

いや、ここはね注意が必要なんですよ。Pythonという言語において「変数」というのは、「オブジェクト」入れるものではないんです。

Pythonにおける「変数」と「オブジェクト」の関係性を学んでいきましょう。

Pythonの「変数」が管理する情報とは?

C言語やJavaといった言語の「変数」と、Ptyhonの「変数」は同じように見えても情報の管理方法が違います。

C言語の変数定義

char num = 10;

Pythonの変数定義

num = 10

C言語の「変数」は変数自身が情報を管理していますが、Pythonの「変数」は、オブジェクトを参照するための『オブジェクトID』を管理しています

変数の情報管理方法の違い

つまり、Pythonにおける変数の役割とは

『オブジェクト』を参照するための道具

なのです。

Pythonで正確に情報を操るためには、「変数」が「オブジェクトへの参照」を管理していることを理解することが必須知識となります。

ナナ
ナナ

C言語のような言語とは異なる情報の管理方法になっているんですね。これこそが、Pythonのデータ管理の柔軟性を作り出しているのです。

Pythonにおける「変数への代入」の本当の意味とは

ここまで「num = 1」といったプログラムを作ってきましたが、このプログラムの本当の意味は

num変数に「1」を設定している

ではなく

num変数に「1」というオブジェクトへの参照を設定している

が、正しい表現方法です。

次のプログラムでその意味を確認してみましょう。

# 「1」という数のオブジェクトIDを表示
print("1:", id(1))

# 変数へ「1」オブジェクトへの参照を設定
num1 = 1
num2 = 1

# 変数が示すオブジェクトIDを表示
print("num1 -->", id(num1))
print("num2 -->", id(num2))
1: 140719500145488
num1 --> 140719500145488
num2 --> 140719500145488

このように変数「num1」と「num2」のオブジェクトIDは共に「1」というオブジェクトIDと同じになっていますね。

このプログラムの「変数」と「オブジェクト」の関係を図示化してみましょう。

変数への代入の本当の意味

このように「1」というオブジェクトが1つ存在しており、「num1 = 1」と「num2 = 1」は、オブジェクト「1」への参照を「変数」に対して設定しているのです

id関数の引数に「変数」を指定した場合の動作

ちなみに「id関数」は、次のように引数を変数として与えることもできます。

書式
 id(変数名

使用例
 id(num)

意味
 変数が参照しているオブジェクトIDを取得する。

id関数に変数を与えた場合は、変数が参照しているオブジェクトIDが取得されることに注意しましょう。

ナナ
ナナ

id関数に変数を渡すと「変数」自身のオブジェクトのIDが取れるように思ってしまいがちですが違います。

Pythonにおいて変数自身は『オブジェクト』ではありません。変数が参照しているオブジェクトIDが取得されます。

スポンサー

変数の参照が切り替わる実例プログラムの紹介

Pythonの「変数」ってC言語の変数となんか違うなーっと思ってましたが、これがその違和感の正体だったのですね。なるほどー。

でも、変数がオブジェクトの参照を管理しているっていうのが、プログラムの中でどのような動きなのかが、まだイメージを掴めていません。

ナナ
ナナ

それじゃあ、簡単なプログラムを使ってプログラムの流れとともに、変数の参照がどのように変わっていくかを見てみようね!

オブジェクトが生成され、変数がどのように参照を更新していくのかを解説しましょう。

オブジェクトの参照が切り替わるプログラム例

次のプログラムは、シーン1~3に分けてオブジェクトの生成と、変数の参照の切り替わりを表現したものです。

# シーン1:オブジェクトの生成とIDの表示
print("オブジェクトの生成")
print("1:", id(1))
print("2:", id(2))

# シーン2:変数へのオブジェクトの参照設定
num1 = 1
num2 = 1
print("参照先設定直後")
print("num1 -->", id(num1))
print("num2 -->", id(num2))

# シーン3:num2の参照先更新
num2 += 1
print("更新後の参照先")
print("num1 -->", id(num1))
print("num2 -->", id(num2))
オブジェクトの生成
1: 140719500145488
2: 140719500145520
参照先設定直後
num1 --> 140719500145488
num2 --> 140719500145488
更新後の参照先
num1 --> 140719500145488
num2 --> 140719500145520

シーン1:オブジェクトの生成とID表示

シーン1では、オブジェクトの生成が行われています。

print("オブジェクトの生成")
print("1:", id(1))
print("2:", id(2))

id関数の引数に「1」「2」の数値を指定したことにより、Pythonのプログラムではこの瞬間「オブジェクトを作ろう!」ということになります。

シーン1:オブジェクトの生成

オブジェクトが生成されたため、オブジェクトIDが付与され、次のようにprint関数で表示ができることになります。

オブジェクトの生成
1: 140719500145488
2: 140719500145520

シーン2:変数へのオブジェクトの参照設定

次に2つの変数「num1」「num2」に対してオブジェクトの参照を設定しています。

num1 = 1
num2 = 1
print("参照先設定直後")
print("num1 -->", id(num1))
print("num2 -->", id(num2))

「1」という数値のオブジェクトはすでに存在しているため、このプログラムではオブジェクトの生成は行われません。

シーン2:オブジェクトの変数設定

「変数」に対して、オブジェクトの参照設定ができたため、「num1」「num2」に対するid関数の結果は「1」というオブジェクトIDが取得できることになります。

参照先設定直後
num1 --> 140719500145488
num2 --> 140719500145488

このようにシーン1にて作成されたオブジェクトIDを「num1」「num2」が共に参照していることがわかりますね。

シーン3:変数「num2」の参照先の更新

それでは、変数「num2」に対して+1を行い「2」という情報を管理するように変更してみます。

num2 += 1
print("更新後の参照先")
print("num1 -->", id(num1))
print("num2 -->", id(num2))

「2」というオブジェクトは、シーン1ですでに作成済みですね。そのため、変数「num2」はすでに生成済みのオブジェクト「2」へ参照先が切り替わるように処理されます。

シーン3:オブジェクト参照先の更新

結果、確かに次のように「2」のオブジェクトに参照先が変更されているのがわかります。

更新後の参照先
num1 --> 140719500145488
num2 --> 140719500145520

「オブジェクトの生成」と「変数のオブジェクト参照」の関係性をしっかりと理解しましょう。

スポンサー

Q&A:Pythonのオブジェクトに関するよくある質問

ナナ
ナナ

オブジェクトについて質問ある人はどうぞ!

Q:「id関数」は引数にオブジェクトも変数でも指定できるって不思議です?どうしてなの?

師匠!なんで「id関数」にはオブジェクトを指定することもできて、変数を指定することもできるんですか?

ナナ
ナナ

いや、それはね、実はちょっと違うんですよ。「id関数」の引数自体はやっぱりオブジェクトしか受け取れません。

次のように、id関数には「オブジェクト」も「変数」も指定することができます。

# 変数にオブジェクトの参照を設定
data = 10

# id関数の呼び出し
print(id(10))       # オブジェクトを指定
print(id(data))     # 変数を指定
140719500145776
140719500145776

ただし、変数を渡しているようで、実は変数ではないのです。

オブジェクトを参照している変数は、プログラムで使用すると参照先オブジェクトとして置き換えられます。そのため、結局はオブジェクトとして解釈されます。

id関数の引数はオブジェクト
ナナ
ナナ

変数への代入のときは、変数への参照設定として解釈されますが、変数を利用するときは、参照先のオブジェクトとして解釈されます。

スポンサー

C言語技術者が知るべきPython言語との違い:変数の扱い

ナナ
ナナ

すでにC言語を習得している人は、次のポイントに気を付けよう!

C言語技術者が知るべきPythonの特徴
  • Pythonは真の「オブジェクト指向言語」である
  • Pythonの「変数」はC言語の「変数」とは異なり、情報を直接管理せずオブジェクトを参照するための情報を管理している。
  • C言語で言うところの「ポインタ変数」に近い存在である。

Pythonにおける「変数」は、C言語においては「ポインタ変数」にイメージが似ています。

  • C言語の「ポインタ変数」とは、とあるメモリ(変数)を参照するための道具
  • Pythonの「変数」とは、とあるオブジェクトを参照するための道具

C言語

char Num = 10;
char * pNum = &Num;

Python

num = 10

C言語のポインタとの類似性

C言語の「ポインタ変数」はchar*型というように参照先のデータ型の情報を管理しています。

しかし、Pythonの「変数」は変数自身はデータ型を管理していません。オブジェクト側がデータ型を管理しているのです。

そのため、Pythonの「変数」には、数でも文字列でも好きなタイミングでオブジェクトの参照を設定することが可能となります。

# 参照先を整数値オブジェクトに設定
data = 10
print(data, "ID:", id(data))

# 参照先を文字列オブジェクトに設定
data = "Hello"
print(data, "ID:", id(data))

# 参照先をリストオブジェクトに設定
data = [0, 1, 2]
print(data, "ID:", id(data))
10 ID: 140719500145776
Hello ID: 2299682313304
[0, 1, 2] ID: 2299681858056

これは変数自身がデータ型を管理していない構造となっているため、可能なプログラムなのです。

自由にオブジェクトを参照できる変数
ナナ
ナナ

変数側に型情報を持たせないことにより、変数を扱う自由度を引き上げているのがPythonの「変数」なんです。C言語とは全く異なるアプローチですね。