順番に読み進めながら学べます

クラスとインスタンス — 自分だけの型を定義する

Python のクラスとインスタンスを基礎から解説します。class の定義、self の役割、__init__ で属性を初期化する基本までを図解で押さえます。

前回の型まとめで触れたとおり、intstrlistdict といった組み込み型だけでは「ユーザー」「商品」「注文」のような業務上の概念をそのまま表せません。今回はその次のステップとして、class で自分だけの型を定義する書き方 — オブジェクト指向プログラミング(OOP)を整理します。

なぜオブジェクト指向か

ここまで学んだ書き方は 手続き型 と呼ばれ、関数を組み合わせて処理を組み立てるスタイルでした。プログラムが大きくなると、関連するデータと処理がコードのあちこちに散らばるようになり、変更や再利用が難しくなります。

オブジェクト指向プログラミング(OOP) では、関連するデータ(属性)とそれに対する操作(メソッド)を 1 つのまとまり — オブジェクト — としてくくります。これにより、現実世界の概念のかたまりに合わせてコードを設計できるようになります。

手続き型 vs オブジェクト指向 — データと関数の関係
手続き型データ(変数)関数(別の場所)OOPオブジェクトデータ + メソッド1 つに一体化別物 (毎回渡す)結果
手続き型ではデータと関数が 完全に別の場所 にあり、関数(データ) のように毎回データを渡して使う。OOP は両者を オブジェクトの中 に同居させ、一体として扱う。

クラスは設計図、インスタンスは実体

OOP の中心となる 2 つの言葉を押さえましょう。

- クラス(class) — 「どんな属性とメソッドを持つか」を書いた 設計図

- インスタンス(instance) — クラスをもとに作られる 実体

たとえば「商品」という概念を Product クラスとして定義すれば、そこから「リンゴ」「バナナ」「みかん」といった個別の商品インスタンスをいくつでも作れます。クラスとインスタンスをまとめて オブジェクト と呼びます。

クラスから複数のインスタンスを作る
Product(クラス)applename='りんご'banananame='バナナ'orangename='みかん'生成生成生成
クラスは型紙のようなもので、それ自体は使う対象にならない。クラスから生まれる実体(インスタンス)が実際にデータを持ち、メソッドを呼ばれる。

最小のクラスを定義してみる

では実際に、商品を表す Product クラスを定義してみましょう。クラスは class クラス名: という構文で書きます。Python ではクラス名は 大文字始まりのキャメルケースProductUserAccount など)にするのが慣習です。

クラスの中に直接 name = "りんご" のように書いた変数は、クラスが持つ既定値として扱われ、Product.name のように クラス名から直接アクセス できます。

class Product:
    name = "りんご"
    price = 150

# クラスから直接アクセスできる
print(Product.name)    # りんご
print(Product.price)   # 150
クラス本体に張り付く変数 — クラス変数
Product(クラス本体)name='りんご'price=150持つ持つ
class のインデント直下に書いた name / price は、クラスそのものに張り付く変数で、Product.name のようにクラス名から直接読める。

このように class 直下に書いた変数はすべて クラス変数 と呼ばれる種類です。インスタンスごとに別々の値を持たせる インスタンス変数 とは性質が違いますが、その違いは後の記事で改めて整理します。今は 「クラス自身に値を張り付けて、Product.name で読める」 という最小形だけ理解できれば十分です。

在庫管理を題材にクラスを 1 つ作ってみます。

class Product: を定義してください。

② クラスの中に name = "りんご"price = 150stock = 10 の 3 つを書いてください。

print(Product.name) / print(Product.price) / print(Product.stock) の 3 行を実行し、クラス名から直接値を取り出せることを確認してください。

(正しく実行できれば解説が表示されます)

Python エディタ

コードを実行してください

__init__ でインスタンスごとに違う値を持たせる

上の最小クラスは name = "りんご" のような 固定値 をクラスに張り付けていただけなので、これだとどんなインスタンスを作っても全部「りんご」になってしまいます。実際の業務では、1 つのクラスから「りんご」「バナナ」「みかん」のように違う値を持つインスタンスを いくつでも作りたいはずです。

そのために使うのが、Python の特別なメソッド __init__コンストラクタ とも呼ばれる初期化メソッドです。Product("りんご", 150) のように引数付きで呼び出すと、Python が自動的に __init__ を呼び出し、その中で self.name = name のように そのインスタンス専用の属性 に値を書き込めます。

アンダースコア 2 つ

__init__ のように アンダースコア 2 つで囲まれた名前 は、Python が特別な意味を持たせている ダンダーメソッド と呼ばれます。インスタンス生成時の __init__print() 表示時の __str__ など多数あり、それぞれ 自動的に呼び出されるタイミング が決まっています。__init__ の詳しい使い方や、対になる __del__次回の記事 で改めて扱います。

class Product:
    def __init__(self, name, price):    # インスタンス生成時に自動で呼ばれる
        self.name = name
        self.price = price

apple = Product("りんご", 150)
banana = Product("バナナ", 80)

print(apple.name, apple.price)     # りんご 150
print(banana.name, banana.price)   # バナナ 80

# apple と banana は別のオブジェクト
print(apple is banana)             # False
Product("りんご", 150) を呼ぶと何が起きるか
apple = Product( 'りんご', 150)__init__(self, name, price)self.name = nameself.price = priceapplename='りんご', price=150自動呼び出し代入完成
Product("りんご", 150) を呼ぶと、Python は ① 空のインスタンスを用意し、② それを self として __init__ に渡し、③ 引数で受け取った値を そのインスタンスの属性 として書き込んで完成させる。
1 つのクラスから複数のインスタンスを作る
Product(クラス)applename='りんご', price=150banananame='バナナ', price=80orangename='みかん', price=120
Product(...) を呼ぶたびに 別の実体 が生まれる。applebananaorange同じ設計図から作られた別のオブジェクト で、それぞれが自分の name / price を持つ。

__init__ を持つ Product クラスを書いて、複数のインスタンスを作ります。

class Product: を定義し、def __init__(self, name, price): の中で self.name = nameself.price = price を書いてください。

apple = Product("りんご", 150)banana = Product("バナナ", 80) の 2 つのインスタンスを作成してください。

print(apple.name, apple.price)print(banana.name, banana.price) を実行し、それぞれが 別の値を持っている ことを確認してください。

(正しく実行できれば解説が表示されます)

Python エディタ

コードを実行してください

メソッドと self の仕組み

属性だけだと「データを置いておけるだけ」で、まだ普通の辞書とそう変わりません。インスタンスに対してできる操作 を一緒に書いておけるのが OOP の本領で、それを メソッド と呼びます。

メソッドと self の決まりごと
class Product:def show(self): ...第 1 引数self (必須)呼び出し元のインスタンスが自動で入るself.name→ 属性参照中に定義宣言中身経由
クラスの中に def で書いた関数が メソッド第 1 引数 self は必須 で、呼び出し時には 「呼び出し元のインスタンス」 が自動で入る。メソッド内では self.name のように書くことで、そのインスタンスの属性にアクセスできる。

apple.show() と書くと、Python は内部的に Product.show(apple) を実行していて、self の中身が apple になります。

self は「呼び出した本人」を指す
モジュール
  • apple, banana は別々のインスタンス
  • apple.show() を呼ぶと…
show(self) のフレーム
  • selfapple が自動的に入る
  • self.nameapple.name を読む
  • banana.show() のときは selfbanana になる
self は固定された値ではなく、メソッドを呼んだそのインスタンスが毎回入る。同じ show メソッドでも、apple から呼べば apple の name が、banana から呼べば banana の name が読まれる。
class Product:
    def __init__(self, name, price):
        self.name = name
        self.price = price

    def show(self):                         # 第 1 引数は必ず self
        print(f"{self.name}: {self.price} 円")

apple = Product("りんご", 150)
banana = Product("バナナ", 80)

apple.show()    # りんご: 150 円  Product.show(apple) と内部的には同じ
banana.show()   # バナナ: 80 円  Product.show(banana) と内部的には同じ
メソッド呼び出し時に self が決まる
apple.show()self = appleりんご: 150 円banana.show()self = bananaバナナ: 80 円渡す出力渡す出力
apple.show() を呼ぶと self に apple が入りbanana.show() のときは self に banana が入る。同じ show メソッドでも、呼び出したインスタンスごとに別の self で動く。

Product にメソッドを 1 つ追加して、インスタンス経由で呼び出します。

class Product: を定義し、__init__(self, name, price)self.name / self.price を初期化してください。

② クラス内に def show(self): を定義し、print(f"{self.name}: {self.price} 円") を表示してください。

apple = Product("りんご", 150)banana = Product("バナナ", 80) を作り、apple.show()banana.show() をそれぞれ呼び出して、同じメソッドが各インスタンスの値で動く ことを確認してください。

Python エディタ

コードを実行してください

self は単なる「慣習」

Python 文法上は第 1 引数の名前は何でもよく、def show(this): でも動きます。ただしほぼすべての Python コードが self を使っているため、揃えるのが鉄則です。self 以外を使うと読み手の混乱を招きます。

今回の記事では、オブジェクト指向の基本を学びました。変数やメソッドにはのちの記事でより詳細に解説します。

QUIZ

理解度チェック

まずは1問ずつ答えてみましょう。

Q1次のうち、Python のクラス定義 として正しいものはどれですか?

Q2メソッドの第 1 引数 self には、呼び出し時に何が自動的に渡されますか?

Q3次のコードを実行したときの出力はどれですか?
class P:
def __init__(self, x):
self.x = x
a = P(10)
b = P(20)
print(a.x + b.x)