Pythonのクラスで最初に戸惑いやすいのがself
という引数です。
これはインスタンスメソッドの第一引数に現れ、オブジェクト自身を指す参照として働きます。
本記事ではselfが何者で、なぜ必要で、どのように正しく使うかを、初心者向けに段階的に解説します。
エラー例や実行結果も交え、混乱しやすい点を丁寧に整理します。
selfとは何か(Pythonのクラス/メソッド基礎)
selfはインスタンス自身への参照
selfは「そのメソッドが呼ばれているオブジェクト自身」を指す参照です。
これにより、そのオブジェクトの属性や他のメソッドにアクセスできます。
# selfが「自分自身」を指すことを確認する例
class Box:
def set_value(self, value):
# インスタンスの属性valueに値を保存
self.value = value
def show_ids(self):
# id()はオブジェクトの「同一性」を表す整数を返します
print("id(self) =", id(self))
b = Box()
print("id(b) =", id(b))
b.set_value(42)
b.show_ids() # selfはbと同じオブジェクトを指す
id(b) = 140630213983600
id(self) = 140630213983600
このようにselfと変数bは同一の実体です。
メソッド中でself.value
と書けば、そのインスタンス固有の値にアクセスできます。
selfはキーワードではない(第一引数の慣習)
selfは予約語ではなく、あくまで「第一引数の名前の慣習」です。
別名でも動きますが、可読性と慣習に従い必ずselfを使いましょう。
# 技術的にはself以外の名前でも動くが、非推奨の例
class Counter:
def inc(this, step=1): # 動くが慣習に反する
if not hasattr(this, "n"):
this.n = 0
this.n += step
c = Counter()
c.inc()
print(c.n) # 1
1
PEP 8(スタイルガイド)でもインスタンスメソッドの第一引数はselfにすることが示されています。
呼び出しの仕組み: obj.m() -> Class.m(obj)
obj.m()という記法は、実際にはClass.m(obj)
という関数呼び出しに変換されます。
インスタンスから属性を取り出すと、関数がバウンドメソッドに変換され、第一引数に自動でobjが渡されます。
class Greeter:
def hello(self, name):
print(f"Hello, {name}! I am {id(self)}")
g = Greeter()
# インスタンスから呼ぶ(自動でself=gが渡される)
g.hello("Alice")
# クラスから関数として取り出し、明示的にインスタンスを渡す
Greeter.hello(g, "Bob")
# 取り出したメソッドオブジェクトの中身を観察
bound = g.hello
print("bound.__self__ is g:", bound.__self__ is g) # バインド先のインスタンス
print("bound.__func__ is Greeter.hello:", bound.__func__ is Greeter.hello)
Hello, Alice! I am 140630213983840
Hello, Bob! I am 140630213983840
bound.__self__ is g: True
bound.__func__ is Greeter.hello: True
この変換ルールがあるため、メソッド定義の第一引数が必要になります。
なぜselfが必要か(属性と状態管理)
オブジェクトはそれぞれ独立した状態を持ちます。
selfを介して各インスタンスの状態(属性)を読み書きします。
# 2つのウォレットがお互いに影響しないことを示す
class Wallet:
def __init__(self, owner, balance=0):
self.owner = owner # インスタンス固有の属性
self.balance = balance # インスタンス固有の属性
def deposit(self, amount):
self.balance += amount # 自分の残高だけが増える
def __str__(self):
return f"{self.owner}: {self.balance}円"
w1 = Wallet("Alice", 1000)
w2 = Wallet("Bob", 500)
w1.deposit(300)
print(w1) # Alice: 1300円
print(w2) # Bob: 500円
Alice: 1300円
Bob: 500円
w1の操作はw2に影響しません。
selfは、この分離された状態管理の要です。
selfとthisの違い(他言語)
JavaやC++のthis
は暗黙に渡されますが、Pythonは明示的に第一引数(self)で受け取る哲学です。
これにより、メソッドは「ただの関数」で、束縛の仕組みが透けて見えるため、挙動が理解しやすくなります。
selfの使い方と書き方
__init__とself(初期化と属性定義)
コンストラクタ__init__
はインスタンス生成直後に呼ばれ、selfを使って属性を初期化します。
すべてのインスタンス属性は__init__で定義するのが基本です。
class Person:
def __init__(self, name, age):
# ここでインスタンス属性を生やす
self.name = name
self.age = age
def greet(self):
print(f"Hi, I'm {self.name} ({self.age})")
p = Person("Carol", 20)
p.greet()
Hi, I'm Carol (20)
インスタンスメソッドの第一引数はself
インスタンスメソッドは定義上最初の引数で自分自身(self)を受け取る必要があります。
これは呼び出し規則(obj.m() → Class.m(obj))の結果です。
class Thermometer:
def set_celsius(self, c):
self.c = c
def as_fahrenheit(self):
return self.c * 9 / 5 + 32
t = Thermometer()
t.set_celsius(25)
print(t.as_fahrenheit())
77.0
属性アクセスはself.が必須
メソッド内でインスタンス属性に触れるときは必ずself.プレフィックスが必要です。
単なるname
はローカル変数を指し、意図した属性にアクセスできません。
class Sample:
def __init__(self, v):
self.v = v
def wrong(self):
v = 99 # ローカル変数。self.vは変わらない
return v
def correct(self):
self.v = 99 # インスタンス属性を更新する
return self.v
s = Sample(10)
print(s.wrong(), s.v) # ローカルだけが99
print(s.correct(), s.v) # 属性が99に更新される
99 10
99 99
self.を書かないと別物になる点に注意してください。
selfを省略できない理由
Pythonは「明示は黙示に勝る」という原則で設計されています。
メソッドがどのインスタンスに対して動くかを明示するため、第一引数が必要です。
仮に省略を許すと、関数とメソッドの区別やバインディング挙動が不透明になります。
よくあるエラーと対処(missing ‘self’)
最頻出のエラーはselfを書き忘れることです。
症状と直し方を確認します。
# 典型的なミス: selfを定義し忘れる
class Oops:
def greet(): # ← selfがない
print("hello")
x = Oops()
# インスタンスから呼ぶと、Pythonは暗黙にインスタンスを1つ渡す
x.greet()
Traceback (most recent call last):
...
TypeError: Oops.greet() takes 0 positional arguments but 1 was given
修正は第一引数にselfを追加するだけです。
class Fixed:
def greet(self): # ← selfを追加
print(f"hello from {id(self)}")
Fixed().greet()
hello from 140630213985040
selfを使わないメソッドとの違い
@classmethodはclsを受け取る
クラスメソッドはクラス自体を第一引数(cls)に受け取るメソッドです。
ファクトリメソッドなどに向いています。
class User:
def __init__(self, name):
self.name = name
@classmethod
def from_csv(cls, line):
# クラスを参照するので、継承先でも正しく動く
name = line.strip().split(",")[0]
return cls(name)
u = User.from_csv("dave,admin")
print(isinstance(u, User), u.name)
True dave
@staticmethodはself不要
スタティックメソッドはselfもclsも受け取らない、ただの名前空間付き関数です。
ユーティリティ計算などに使います。
class Math:
@staticmethod
def add(a, b):
return a + b
print(Math.add(2, 3))
m = Math()
print(m.add(4, 5)) # インスタンス経由でも呼べるがselfは渡されない
5
9
バウンドメソッドとアンバウンドの違い
Python 3では「アンバウンドメソッド」型は存在せず、クラスから取り出したものは単なる関数です。
一方、インスタンスから取り出すとバウンドメソッドになります。
class Echo:
def say(self, msg):
print(f"[{id(self)}] {msg}")
e = Echo()
# クラスから取り出す → 関数(未バインド)
func = Echo.say
print(type(func), hasattr(func, "__self__"))
# インスタンスから取り出す → バウンドメソッド
bound = e.say
print(type(bound), hasattr(bound, "__self__"))
print("bound.__self__ is e:", bound.__self__ is e)
# 未バインド関数は自分でインスタンスを渡して呼ぶ
func(e, "manual call")
<class 'function'> False
<class 'method'> True
bound.__self__ is e: True
[140630213985808] manual call
この違いを理解すると、obj.m()とClass.m(obj)の等価性が腹落ちします。
selfのベストプラクティス
命名は必ずselfにする
PEP 8に従い第一引数名はselfに統一しましょう。
チーム内で表記が揺れると理解コストが高まります。
短いスコープでもthisやsなどの別名は避けるべきです。
# 良い例
class Good:
def do(self): # selfで統一
pass
# 悪い例(非推奨)
class Bad:
def do(this): # チーム開発では混乱のもと
pass
属性は__init__で定義して一貫性を保つ
すべてのインスタンス属性は__init__で生やすと、どのメソッドからも存在が保証され、補完や型推論にも有利です。
条件分岐の深い場所で唐突にself.x = ...
を作るのは避けます。
class Profile:
def __init__(self, name):
self.name = name
self.tags = [] # ここで宣言しておく
self.active = True # 既定値もまとめる
def deactivate(self):
self.active = False # 既に存在する属性を更新
Self型ヒント(Python 3.11+)の活用
Python 3.11以降はtyping.Self
で「自分自身を返す」型を表現できます。
流れるようなAPI(メソッドチェーン)の型安全性が向上します。
# Python 3.11+
from typing import Self
class Builder:
def __init__(self):
self.parts: list[str] = []
def add(self, part: str) -> Self:
self.parts.append(part)
return self # Selfに適合する(同じインスタンスを返す)
def build(self) -> str:
return "-".join(self.parts)
b = Builder().add("A").add("B")
print(b.build())
A-B
Selfは継承関係でも正しく派生型を推論するため、メソッドチェーンを多用する設計で特に効果があります。
以下に3種のメソッドの要点を整理します。
種類 | 第一引数 | 目的 | 呼び出し例 |
---|---|---|---|
インスタンスメソッド | self | 個々のオブジェクトの状態を操作 | obj.m(), Class.m(obj) |
クラスメソッド | cls | クラス全体に関わる処理、代替コンストラクタ | Class.m(), SubClass.m() |
スタティックメソッド | なし | 補助的な独立処理(名前空間として提供) | Class.m(), obj.m() |
「状態を触るならself」「クラスに紐づく操作はcls」「どちらにも触れないならstaticmethod」と覚えると迷いにくいです。
まとめ
selfはインスタンス自身への明示的な参照であり、obj.m() → Class.m(obj)という呼び出し変換のもとに機能します。
属性へのアクセスや状態管理にはself.が必須で、第一引数の書き忘れは典型的なTypeErrorの原因です。
classmethodとstaticmethodとの差も理解し、PEP 8に従って第一引数名はselfで統一してください。
Python 3.11以降はtyping.Self
でメソッドチェーンの型安全性を高められます。
以上を押さえれば、クラス設計とメソッド定義が一層明快になり、実践で迷う場面が大きく減ります。