クラスはデータとその振る舞いをまとめるもの
Python のクラスを使うと、「ユーザー」「銀行口座」「設定」「リクエスト」といった何かの種類と、それができる操作をひとまとめに定義できます。この「何か」にあたるのがクラスのインスタンスで、操作のことをメソッドと呼びます。
まずは、もっともシンプルなクラスの例を見てみましょう。
分解して見ていきましょう。
class User:でクラス定義が始まります。クラス名は慣例としてパスカルケースで書きます。__init__はイニシャライザです。新しいインスタンスを作ったタイミングで自動的に呼ばれ、self.なんとか = ...の形でインスタンスの属性を用意します。greetはメソッドです。selfは、そのメソッドが呼ばれた対象のインスタンスを指すための名前です。User("Rosa", "rosa@example.com")でインスタンスを生成します。Python はselfに新しいインスタンスをセットし、残りの引数をそのまま渡して__init__を呼び出します。user.greet()でメソッドを呼び出します。このときuserが自動的にselfとして渡されます。
self は単なる第一引数
self はキーワードではありません。インスタンスメソッドの第一引数、つまり「そのメソッドが動いている対象のインスタンス」を指す名前として、Python が慣習的にそう呼んでいるだけです。別の名前を付けることも_できます_が、みんなが self を使うから自分も self を使う、というのが実情です。
インスタンスメソッドは必ず第一引数に self を取ります。これがあるからこそ、メソッドはどのインスタンスの値を読み書きすればいいのかを把握できるのです。
振る舞いを追加する
メソッドは状態を読むことも書き換えることもできます。
__repr__ もまた特殊メソッドのひとつで、「このオブジェクトを表示するときどう見せるか?」を決めるフックです。ここをきちんと書いておくと、デバッグのときに本当に助かります。
クラス変数とインスタンス変数の違い
クラス本体(__init__ の外側)で定義した属性は、すべてのインスタンスで 共有 されます。一方、self に代入した属性は インスタンスごと に持たれます。
クラス属性は、本当の意味で「全インスタンスで共有される値」にだけ使いましょう。定数やカウンタ、設定値などが典型例です。一方、インスタンスごとに異なるデータは __init__ の中で定義します。
継承(inheritance)
Python では、あるクラスを別のクラスから 継承 させることができます。継承すると、親クラスのメソッドや属性をそのまま受け継げるので、必要な部分だけ追加したりオーバーライドしたりすれば OK です。
super() を使うと親クラスにアクセスできます。よく使うのは __init__ の中で、自分の属性を追加する前に親クラスの属性を初期化するパターンです。
継承は便利な仕組みですが、つい使いすぎてしまいがちです。Python を始めたばかりの人は、本当はコンポジション(オブジェクトを属性として持たせる設計)で十分なところに、反射的に継承を持ち出してしまうことがよくあります。まずはフラットなクラス構成から始めて、本当に「〜は〜の一種である(is-a)」と言える関係になったときだけ継承を導入するのがおすすめです。
dataclass:データ保持クラスの決定版
「いくつかの属性を持たせて、等価比較や文字列表現もいい感じにしてほしい」——そんな用途がメインなら、@dataclass を使うとボイラープレートを大幅に減らせます。
これを手作業で __init__、__repr__、__eq__ を書くのと比べてみてください。属性を代入するだけの __init__ しかないような class Thing を書きそうなときは、dataclass を真っ先に検討するのが正解です。
@property で計算プロパティを作る
「属性」と言いつつ、実は裏で計算されている値を扱いたいときがあります。そんなときは @property を使うと、ふつうの属性アクセスのように書けます。
プロパティを使うべきなのは、obj.get_something() のように書きたくなる場面です。プロパティに置き換えると、APIがぐっと自然に感じられます。一方で、重い処理を隠す用途には向きません。属性アクセスは速いもの、というのが利用側の感覚だからです。
「プライベート」は慣習で決まる
Pythonには本当の意味でのprivateはありません。慣習として、アンダースコアで始まる属性は プライベートのつもり という扱いになり、クラスの外から触らないのがお約束です。
class Cache:
def __init__(self):
self._store = {}
def put(self, key, value):
self._store[key] = value
def get(self, key, default=None):
return self._store.get(key, default)
アンダースコア2つで始まる名前(__name)は ネームマングリング の対象となり、属性名にクラス名が自動で付加されます。これは継承時に名前が衝突するのを避けるための仕組みであって、セキュリティ機能ではありません。
クラスを使わなくていい場面
関連するデータをまとめたいだけなら、dataclass や普通の辞書、あるいは名前付きタプル (namedtuple) で十分です。関数が1つあるだけなら、わざわざクラスで包む必要もありません。クラスの出番は、状態(データ)とふるまい(メソッド)がセットになっているとき、特に同じ種類のインスタンスをいくつも作るようなケースです。
最後にサンプルをひとつ
ファイルっぽく使える、小さなログバッファを書いてみましょう。
ここで登場している __len__ もマジックメソッドの一種です。これを定義しておくと len(logger) が動くようになります。というのも、len(x) は内部的には x.__len__() を呼び出しているだけだからです。Python にはこうしたフックが何十種類も用意されていますが、必要になったタイミングで覚えていけば十分です。
次のテーマ:ジェネレータ
クラスはデータと振る舞いをひとつにまとめる仕組みでした。次の章では、ちょっと毛色の違う抽象化である「反復処理」を取り上げます。最初に扱うのはジェネレータ——値を一度にひとつずつ生成し、その合間は処理を一時停止しておける関数です。さらにその直後に登場する with 文(コンテキストマネージャ)とも相性抜群なので、合わせて楽しみにしていてください。
よくある質問
Pythonのクラスとは何ですか?
クラスは、データ(属性)とふるまい(メソッド)をひとつにまとめたオブジェクトを作るための設計図です。class User: と書けばUserクラスを定義でき、User(...) でインスタンスを生成できます。状態とふるまいをあわせ持つ「モノ」をモデリングする際に、Pythonで最もよく使われる仕組みです。
Pythonの self って何ですか?
self はインスタンスメソッドの第一引数で、そのメソッドを呼び出したインスタンス自身を指します。たとえば user.greet() を呼ぶと、Pythonが user を self として自動で渡してくれます。メソッド内で self.name と書けばそのユーザーの name 属性にアクセスできます。self は予約語ではなく慣習ですが、Pythonを書く人はみんなこの名前を使います。
Pythonはオブジェクト指向言語ですか?
はい。Pythonでは数値・文字列・関数にいたるまで、すべてがオブジェクトです。ただし完全なオブジェクト指向を強制されるわけではなく、必要な場面だけクラスを使えばOKです。実務のPythonコードでは、クラスを多用せず普通の関数やデータ構造で済ませることも多いです。