| この記事の要点 |
|
クラスとメソッドの最小形
class User:
def __init__(self, name, age): # 初期化。インスタンス生成時に呼ばれる
self.name = name # インスタンス属性
self.age = age
def greet(self): # インスタンスメソッド
return f"{self.name}({self.age}歳) です"
def birthday(self):
self.age += 1 # 自分の状態を変える
return self.age
u = User("田中", 30) # new は要らない
print(u.greet()) # 田中(30歳) です
print(u.birthday()) # 31
print(u.name) # 田中 属性に直接アクセスできる
定義には self を書き、呼び出しには書きません。u.greet() は内部的に User.greet(u) として実行されます。self を書き忘れると TypeError: greet() takes 0 positional arguments but 1 was given になります。
メソッドの 3 種類
| 種類 | 第 1 引数 | 使う場面 |
|---|---|---|
| インスタンスメソッド | self | そのインスタンスの状態を読み書きする |
@classmethod | cls | 別の作り方を提供する(ファクトリ)、クラス変数を扱う |
@staticmethod | なし | 状態を使わないがクラスに置きたい補助処理 |
class User:
species = "human" # クラス変数(全員で共有)
def __init__(self, name):
self.name = name
def greet(self): # インスタンスメソッド
return f"{self.name} です"
@classmethod
def from_csv(cls, line): # 別の作り方
name = line.split(",")[0]
return cls(name) # cls は User。継承先では子クラスになる
@staticmethod
def is_valid(name): # self も cls も使わない
return bool(name) and len(name) <= 20
print(User.from_csv("田中,30").greet()) # 田中 です
print(User.is_valid("")) # False
@classmethod で cls(...) と書くのがポイントです。User(...) と直書きすると、継承したクラスから呼んだときに親クラスのインスタンスができてしまいます。
クラス変数とインスタンス変数
class Counter:
total = 0 # クラス変数
log = [] # ← 危険。全インスタンスで共有される
def __init__(self):
Counter.total += 1
self.count = 0 # インスタンス変数
a, b = Counter(), Counter()
print(Counter.total) # 2
a.log.append("x")
print(b.log) # ['x'] ← b にも見えてしまう
リストや辞書をクラス直下に書くと1 個の実体を全員で共有します。個別に持たせたいものは必ず __init__ の中で self.log = [] と作ります。詳細は クラス変数とインスタンス変数 を参照してください。
公開・非公開の扱い
class Account:
def __init__(self, balance):
self.balance = balance # 公開
self._rate = 0.01 # 内部用(触らないでほしい、の合図)
self.__secret = "x" # 名前マングリングされる
a = Account(100)
print(a._rate) # 0.01 アクセスできてしまう
# print(a.__secret) # AttributeError
print(a._Account__secret) # x 実際はこの名前になっている
Python に private キーワードはありません。アンダースコアは規約による意思表示で、強制力はありません。
getter / setter は書かない
class Product:
def __init__(self, price):
self.price = price # まずは素直な属性でよい
@property
def tax_included(self): # 呼び出し側は p.tax_included と書ける
return int(self.price * 1.1)
p = Product(1000)
print(p.tax_included) # 1100 かっこは不要
実務では次のように書きます。あとから検証を足したくなったときだけ @property に変えるのが Python 流です。呼び出し側のコードは変えずに済みます。
class Product:
def __init__(self, price):
self._price = price
@property
def price(self):
return self._price
@price.setter
def price(self, value):
if value < 0:
raise ValueError("価格は 0 以上にしてください")
self._price = value
p = Product(1000)
p.price = 1200 # setter が呼ばれる
print(p.price) # 1200
p.price = -1 # ValueError
よく使う特殊メソッド
class Point:
def __init__(self, x, y):
self.x, self.y = x, y
def __repr__(self): # デバッグ表示。print やログで役立つ
return f"Point({self.x}, {self.y})"
def __eq__(self, other): # == の比較方法
return (self.x, self.y) == (other.x, other.y)
def __len__(self): # len() が使えるようになる
return 2
print(Point(1, 2)) # Point(1, 2)
print(Point(1, 2) == Point(1, 2)) # True
単純なデータの入れ物なら @dataclass を使うと __init__ と __repr__ と __eq__ が自動生成されます。
from dataclasses import dataclass, field
@dataclass
class Point:
x: int
y: int = 0
tags: list[str] = field(default_factory=list) # 可変な既定値はこう書く
print(Point(1, 2)) # Point(x=1, y=2, tags=[])
self を書き忘れたときの症状
class User:
def __init__(self, name):
self.name = name
def greet(): # self が無い
return "hello"
def rename(self, name):
name = name # self を付け忘れ → ローカル変数を書き換えただけ
u = User("田中")
u.greet() # TypeError: greet() takes 0 positional arguments but 1 was given
u.rename("鈴木")
print(u.name) # 田中 ← 変わっていない
2 つ目はエラーにならないぶん厄介です。「代入したのに反映されない」ときは、self. が付いているかを最初に確認してください。
属性は後から足せる
class User:
def __init__(self, name):
self.name = name
u = User("田中")
u.age = 30 # 定義していない属性を足せてしまう
print(u.__dict__) # {'name': '田中', 'age': 30}
print(getattr(u, "email", "未設定")) # 未設定 無い属性を安全に読む
print(hasattr(u, "age")) # True
# 属性を固定したいなら __slots__
class Point:
__slots__ = ("x", "y")
def __init__(self, x, y):
self.x, self.y = x, y
p = Point(1, 2)
p.z = 3 # AttributeError: 'Point' object has no attribute 'z'
タイプミスした属性名がそのまま新しい属性として作られるため、u.nmae = "鈴木" のような誤りに気づけません。大量に作るクラスでは __slots__ がメモリ削減にもなります。
継承と委譲の使い分け
# 継承: 「A は B の一種である」
class Admin(User):
def __init__(self, name, level):
super().__init__(name)
self.level = level
# 委譲: 「A は B を持っている」
class Report:
def __init__(self, formatter):
self.formatter = formatter # 差し替えられる
def render(self, rows):
return self.formatter.format(rows)
「は〜の一種」と言えないなら継承にしないでください。振る舞いを差し替えたいだけなら、オブジェクトを持たせる(委譲)ほうが柔軟で、テストでも差し替えが簡単になります。詳細は 継承の概念と必要性 を参照してください。
抽象クラスで実装を強制する
from abc import ABC, abstractmethod
class Formatter(ABC):
@abstractmethod
def format(self, rows) -> str:
...
class CsvFormatter(Formatter):
def format(self, rows) -> str:
return "\n".join(",".join(r) for r in rows)
class Broken(Formatter):
pass
Broken() # TypeError: Can't instantiate abstract class Broken
# with abstract method format
@abstractmethod を付けたメソッドを実装しないクラスは、インスタンス化しようとした時点でエラーになります。実装漏れを実行時まで持ち越さずに済みます。
関連
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- プロジェクトをTomcatプロジェクトとして認識させる方法 2026-10-07 22:32:50
- MySQLの1366 Incorrect string value|Laravelの文字コード・絵文字エラー 2026-10-07 21:54:03
- curlの証明書ホスト名不一致|旧エラー51・現行60の確認と対処 2026-10-07 21:54:03
- LaravelのMassAssignmentException|fillableの原因と安全な対処 2026-10-07 21:54:03
- Eclipse で Tomcat の起動ログがコンソールに出ない時の確認手順 2026-10-07 21:54:02
- MySQLにおける中央値(Median)の導き方(バージョン8未満) 2026-10-07 13:49:45
- getInputForward 2026-10-07 13:41:15
- JSONから配列に変換 2026-10-07 13:41:15
- ビューから値をモデルに格納しコントローラーで受け取る方法 2026-10-07 13:23:41
- Laravelのテーブル作成と定義変更|マイグレーション・up/down・注意点 2026-10-07 13:23:41
- NumPy 配列に要素を追加する方法 (append / concatenate) 2026-10-07 13:23:41
- MariaDB・MySQLで現在日時を取得する方法|NOW・タイムゾーン・保存型 2026-10-07 13:13:36
- 【django】テンプレートで定数を使用する方法 2026-10-07 13:10:15
- Spring BootにおけるApplication.propertiesの環境依存設定の分割方法 2026-10-07 12:09:35
- Not supported for DML operations【Springエラー】 2026-10-07 11:09:38