CHAPTER 4 ・ コードを整理して育てる / Lesson 15

データと処理をひとまとめにする(クラス入門)

請求書1枚を「1つの物」として扱う。class の読み方と、簡単な作り方を、無理のない範囲で学びます。

目安 22分 ・ インストール不要

このレッスンが終わったら

「クラスは、データ(属性)と処理(メソッド)をひとまとめにした設計図。作った1つ1つをインスタンスと呼ぶ」と言える。

STEP 1

こんな場面、ありませんか?

請求書1枚には、番号・金額・入金額といった複数の情報があります。基礎編では、こうしたデータを辞書にまとめ、計算は別の関数に書きました。

基礎編の書き方:辞書と関数に分けて持つコードは書き換えられます
Ctrl / ⌘ + Enter でも実行
結果
▶ 実行を押すと、ここに結果が出ます

税抜210,000円の請求に、230,000円が入金された、という場面です(税込は231,000円なので、1,000円足りません)。正しく動きますが、関数が増えてくると、困ることが出てきます。

  • データと、それを扱う関数が別々で、「この関数は、どの辞書に使うのか」が分かりにくく、キーを "ammount" と打ち間違えても、実行して初めて KeyError になる

「請求書」というひとまとまりの物として、データと処理を一緒に持てないでしょうか。それができるのが、この回の主役、クラスです。

STEP 2

請求書のクラスを動かしてみる

さきほどと同じ請求書を、クラスで作ります。まず動かしてみてください。読み方は、あとで説明します。

Invoice クラスを作って、請求書を1枚作るコードは書き換えられます
Ctrl / ⌘ + Enter でも実行
結果
▶ 実行を押すと、ここに結果が出ます

231000、1000、False(まだ全額は入金されていない)と表示されました。結果は辞書版と同じですが、inv.with_tax() と、「請求書 inv に、税込にしてと頼む」形で書けるようになりました。

STEP 3

仕組みを読む

クラスは、請求書の設計図です。設計図から作った1枚1枚の請求書をインスタンスと呼びます。上の inv は、Invoice の設計図から作ったインスタンスです。

inv = Invoice("INV-2025-0004", ...) の部品
inv作った請求書につける名前
Invoiceどの設計図から作る?
("INV-2025-0004", ...)最初に渡す材料
クラスを、1行ずつ日本語にしてみる
class Invoice:「Invoice(請求書)」という設計図を作る
def __init__(self, number, amount, ...):請求書を1枚作るときに、最初に自動で動く処理。材料を受け取る
self.number = number受け取った番号を、この請求書の「number」として覚えておく
def with_tax(self):請求書に「税込にして」と頼むための処理を作る
return self.amount * (100 + self.rate) // 100この請求書の金額と税率から、税込の金額を返す

日本語にすると

請求書という設計図を作る。1枚作るときは、番号・金額などを覚えさせる。「税込にして」「残りはいくら?」「入金済み?」と頼めるようにしておく。

self.number のように、請求書が覚えているデータを属性、with_tax のように、請求書に頼める処理をメソッドと呼びます。メソッドの最初にある self は、「自分自身」のことです。inv.with_tax() と呼ぶと、inv が self として自動で渡されます。

inv.numberINV-2025-0004
inv.amount210000
inv.paid230000

self が「自分自身」であることは、self を自分で渡しても同じ結果になることで確かめられます。

inv.with_tax() と Invoice.with_tax(inv) は同じコードは書き換えられます
Ctrl / ⌘ + Enter でも実行
結果
▶ 実行を押すと、ここに結果が出ます
STEP 4

変えて、試す

① 請求書を何枚も作って、集計する。 作った請求書をリストに入れれば、基礎編の for や、Lesson 01 の内包表記で集計できます。未入金(または不足)の請求書を取り出してみます。(入金額は、payments.csv の内容に合わせています)

請求書のリストから、入金が足りないものを探すコードは書き換えられます
Ctrl / ⌘ + Enter でも実行
結果
▶ 実行を押すと、ここに結果が出ます

② 属性を書き換える。表示を整える。 属性は、inv.paid = 231000 のように書き換えられます。また、クラスをそのまま print すると、<__main__.Invoice object at 0x7f...> のような読めない表示になります。__repr__ というメソッドを作ると、表示する文章を決められます。

__repr__ で表示を整え、入金額を書き換えるコードは書き換えられます
Ctrl / ⌘ + Enter でも実行
結果
▶ 実行を押すと、ここに結果が出ます

不足の1,000円が入金されて、残高が 0 になりました。

③ self を書き忘れる。 メソッドの1つ目の self を書き忘れると、エラーになります。

わざと間違える:self を書き忘れたコードは書き換えられます
Ctrl / ⌘ + Enter でも実行
結果
▶ 実行を押すと、ここに結果が出ます

TypeError: Invoice.with_tax() takes 0 positional arguments but 1 was given と出ます。「材料を0個受け取る作りなのに、1個渡された」という意味で、この「1個」が、自動で渡される self です。メソッドには、必ず最初に self を書きます。

STEP 5

自分で書く

お題① 経費1件を表す Expense クラスに、メソッド needs_receipt を足してください。金額が5,000円以上なら True、そうでなければ False を返します。(5,000円は、この回だけの仮のルールです。実際の基準は、社内の規程に従います)

お題①:メソッドを足すコードは書き換えられます
Ctrl / ⌘ + Enter でも実行
結果
▶ 実行を押すと、ここに結果が出ます
ヒントを見る

def needs_receipt(self): を作り、return self.amount >= 5000 とします。属性は self.amount のように、self を付けて読みます。

答えの例を見る
class Expense:
  def __init__(self, applicant, amount):
      self.applicant = applicant
      self.amount = amount

  def needs_receipt(self):
      return self.amount >= 5000

e1 = Expense("田中", 1240)
e2 = Expense("高橋", 42000)
print(e1.needs_receipt(), e2.needs_receipt())

お題② Invoice に、入金の状況を文字で返すメソッド status を足してください。残高が0以下なら "入金済み"、入金が1円以上あって残高があるなら "一部入金"、入金が0円なら "未入金" です。

お題②:status メソッドを作るコードは書き換えられます
Ctrl / ⌘ + Enter でも実行
結果
▶ 実行を押すと、ここに結果が出ます
ヒントを見る

if self.balance() <= 0: で「入金済み」、elif self.paid > 0: で「一部入金」、それ以外は「未入金」を return します。

答えの例を見る
class Invoice:
  def __init__(self, amount, paid=0):
      self.amount = amount
      self.paid = paid

  def balance(self):
      return self.amount * 110 // 100 - self.paid

  def status(self):
      if self.balance() <= 0:
          return "入金済み"
      elif self.paid > 0:
          return "一部入金"
      else:
          return "未入金"

invoices = [Invoice(440000, 484000), Invoice(210000, 230000), Invoice(550000)]
print([i.status() for i in invoices])
STEP 6

仕事ならどう使う?

理解チェックinv = Invoice("INV-2025-0004", 210000) の inv を、何と呼びますか?

理解チェックメソッドの中の self は、何を表しているでしょう?