これまであなたは、数値や文字列といった「データ」と、if
文やfor
文、そして自作の「関数」といった「処理」を別々のものとして学んできましたね。しかし、Pythonの世界の根底には、もっと深遠でパワフルな考え方が流れています。それは、「プログラムに登場するすべてのものは、データと処理をひとまとめにした『モノ(オブジェクト)』である」という考え方です。
今回は、このプログラミングの核心とも言える「オブジェクト」の正体に迫ります。この概念を理解すれば、なぜ今まで何気なく使っていたコードがそのように動くのか、その理由がストンと腑に落ちるはずですよ!
あなたが使ってきた「値」の本当の姿
突然ですが、こんなコードを書いたことはありませんか?
name = "yamazaki"
message = "こんにちは、{}さん".format(name)
print(message)
"こんにちは、{}さん"
という文字列の後ろに .format(name)
とつけると、{}
の部分が name
の中身に置き換わって、「こんにちは、yamadaさん」と表示されます。便利ですよね。
でも、少し不思議に思いませんか? なぜ文字列の後ろにドット(.
)をつけて、まるであたかも「文字列さん、フォーマットお願いします!」と命令するような書き方ができるのでしょう。
その答えこそが、「オブジェクト」です。
Pythonでは、123
のような数値も、"hello"
のような文字列も、[1, 2, 3]
のようなリストも、単なるデータではありません。それぞれが固有の「データ(値そのもの)」と、そのデータを扱うための専用の「処理(関数)」をセットで内蔵した、一つの独立した「モノ(オブジェクト)」なのです。
文字列オブジェクトは、「"hello"
という文字データ」を自分の中に持っているだけでなく、「format
する能力」や「すべてを大文字にする能力(upper
)」、「特定の文字を置き換える能力(replace
)」といった、たくさんの特殊能力(関数)を一緒に持っています。
この、オブジェクトに内蔵されている専用の関数のことを、特別に「メソッド」と呼びます。.format()
は、文字列オブジェクトだけが持っている便利なメソッドの一つだった、というわけです。
my_name = "sato"
# 文字列オブジェクトが持つ upper メソッドを使う
upper_name = my_name.upper()
print(upper_name) # "SATO" と表示される
このように、オブジェクト.メソッド()
という形で、そのオブジェクトが持つ能力を引き出して使うのが、Pythonプログラミングの基本スタイルなのです。
オブジェクトの「設計図」と「実体」
「なるほど、Pythonの世界はオブジェクトで満ち溢れているのか!」と分かったところで、次の疑問が湧いてきますよね。「じゃあ、そのオブジェクト自体は、一体誰がどうやって作っているの?」と。
オブジェクトは、「クラス」という設計図をもとに作られます。
クラスは、いわば「たい焼きの金型」のようなものです。金型には「あんこを入れる場所」や「尻尾の形」といった情報が定義されていますよね。この金型(クラス)を使って焼き上げた、一つ一つのたい焼き(あんこ入り、クリーム入りなど)が「オブジェクト」、あるいは「インスタンス」と呼ばれる実体です。
実際に、簡単なクラスを設計してみましょう。ここでは「ネコ」クラスを考えてみます。
# 「ネコ」というクラス(設計図)を定義する
class Cat:
# この設計図からオブジェクトが作られる瞬間に呼ばれる特殊なメソッド
def __init__(self, name, color):
# このネコに固有のデータ(属性)を持たせる
self.name = name
self.color = color
# このネコができること(メソッド)を定義する
def meow(self):
print("{}「にゃーん」".format(self.name))
# Catクラス(設計図)から、2匹のネコ(オブジェクト)を作る
cat1 = Cat("タマ", "白")
cat2 = Cat("クロ", "黒")
# それぞれのネコが持つデータ(属性)を見てみる
print(cat1.name) # "タマ"
print(cat2.color) # "黒"
# それぞれのネコに鳴いてもらう(メソッドを呼び出す)
cat1.meow() # タマ「にゃーん」
cat2.meow() # クロ「にゃーん」
少し複雑に見えるかもしれませんが、一つずつ見ていきましょう。
class Cat:
で、「Cat」という名前の設計図を作り始めます。__init__
は「初期化メソッド」と呼ばれる特殊なメソッドです。Cat("タマ", "白")
のようにオブジェクトが作られる瞬間に自動的に呼ばれ、そのオブジェクトが持つべき初期データを設定します。ここでself.name = name
のようにして設定された、オブジェクト固有のデータのことを「属性(アトリビュート)」と呼びます。meow
は、このクラスから作られたオブジェクトができる「振る舞い」を定義したメソッドです。cat1 = Cat(...)
やcat2 = Cat(...)
の部分で、設計図から具体的なオブジェクト(インスタンス)を生成しています。
cat1
と cat2
は、同じ Cat
クラスという設計図から作られましたが、それぞれが name
や color
という異なる属性(データ)を持つ、独立した別のオブジェクトになっている点が重要です。
知らないとハマる!オブジェクトの同一性という落とし穴
最後に、オブジェクトを扱う上で非常に重要な「同一性」という概念について説明します。これは、多くの初心者がつまずくポイントなので、しっかり理解してくださいね。
次のコードを見てください。list_a
と list_b
は、どちらも [1, 2, 3]
という同じ中身を持っています。
list_a = [1, 2, 3]
list_b = [1, 2, 3]
# == で比較する (中身が等しいか?)
print(list_a == list_b)
# is で比較する (全く同じモノか?)
print(list_a is list_b)
これを実行すると、一つ目の ==
の結果は True
になります。これは、「二つのリストの中身が等しいですか?」という比較で、その通りなので True
です。
しかし、二つ目の is
の結果は False
になります。is
演算子は、「二つの変数が、メモリ上で全く同じ一つのオブジェクトを指していますか?」という、より厳密な比較を行います。この場合、list_a
と list_b
は、中身こそ同じですが、それぞれが別々に作られた二つの異なるリストオブジェクトです。
例えるなら、全く同じデザインのTシャツが2枚あるようなものです。==
は「デザインは同じ?」と聞いているのに対し、is
は「この2枚は、物理的に全く同じ一枚のTシャツ?」と聞いているようなもの。当然、答えはノーですよね。
では、次の場合はどうでしょう?
list_c = [10, 20, 30]
list_d = list_c # list_c を list_d に代入
# is で比較する
print(list_c is list_d)
# list_d の中身を一つ変えてみる
list_d[0] = 99
# list_c はどうなっている?
print(list_c)
これを実行すると、is
の結果は True
になります。そして、最後の print(list_c)
の結果は、なんと [99, 20, 30]
に変わってしまっています!
list_d = list_c
というコードは、リストをコピーしているのではありません。「list_c
という変数が指しているオブジェクトの住所を、list_d
という変数にも教える」という意味になります。結果として、list_c
と list_d
は、二人で一つのリストオブジェクトを共有している状態になるのです。だから、list_d
を通して中身を変更すると、list_c
から見ても中身が変わってしまう、という現象が起きます。この挙動は、特にリストのような変更可能な(ミュータブルな)オブジェクトを扱う際に、バグの原因となりやすいので、==
と is
の違いと合わせて、絶対に覚えておいてください。
まとめ:世界の解像度が上がるオブジェクト指向
お疲れ様でした!今回は、Pythonプログラミングの根幹をなす「オブジェクト」という考え方を学びました。
- オブジェクト: データ(属性)と処理(メソッド)がセットになった「モノ」。Pythonではすべてがオブジェクトである。
- クラス: オブジェクトを作るための「設計図」。
- インスタンス: クラスという設計図から作られた、オブジェクトの「実体」。
- 同一性:
==
は値が等しいか、is
は全く同一のオブジェクトかを判定する。
オブジェクトという概念を理解すると、Pythonの世界の解像度がグッと上がります。これまでバラバラに見えていたデータと処理が、実は密接に結びついた「モノ」として存在していることが見えてくるはずです。この考え方は「オブジェクト指向プログラミング」と呼ばれ、現代のソフトウェア開発の主流となっています。
さて、自分で部品(クラスやオブジェクト)を設計する方法を学びました。次の章では、Pythonにあらかじめ用意されている便利な部品や、世界中の開発者が作って公開している素晴らしい部品たち(モジュール、ライブラリ)を、どうやって自分のプログラムに組み込んで使うのかを学んでいきます。プログラミングの可能性が、無限に広がりますよ!どうぞお楽しみに!
7章. モジュールとライブラリ活用術
まとめができたら、アウトプットとして演習問題にチャレンジしましょう。