CHAPTER 4 ・ コードを整理して育てる / Lesson 15
データと処理をひとまとめにする(クラス入門)
請求書1枚を「1つの物」として扱う。class の読み方と、簡単な作り方を、無理のない範囲で学びます。
このレッスンが終わったら
「クラスは、データ(属性)と処理(メソッド)をひとまとめにした設計図。作った1つ1つをインスタンスと呼ぶ」と言える。
こんな場面、ありませんか?
請求書1枚には、番号・金額・入金額といった複数の情報があります。基礎編では、こうしたデータを辞書にまとめ、計算は別の関数に書きました。
▶ 実行を押すと、ここに結果が出ます
税抜210,000円の請求に、230,000円が入金された、という場面です(税込は231,000円なので、1,000円足りません)。正しく動きますが、関数が増えてくると、困ることが出てきます。
- データと、それを扱う関数が別々で、「この関数は、どの辞書に使うのか」が分かりにくく、キーを
"ammount"と打ち間違えても、実行して初めてKeyErrorになる
「請求書」というひとまとまりの物として、データと処理を一緒に持てないでしょうか。それができるのが、この回の主役、クラスです。
請求書のクラスを動かしてみる
さきほどと同じ請求書を、クラスで作ります。まず動かしてみてください。読み方は、あとで説明します。
▶ 実行を押すと、ここに結果が出ます
231000、1000、False(まだ全額は入金されていない)と表示されました。結果は辞書版と同じですが、inv.with_tax() と、「請求書 inv に、税込にしてと頼む」形で書けるようになりました。
仕組みを読む
クラスは、請求書の設計図です。設計図から作った1枚1枚の請求書をインスタンスと呼びます。上の inv は、Invoice の設計図から作ったインスタンスです。
inv作った請求書につける名前Invoiceどの設計図から作る?("INV-2025-0004", ...)最初に渡す材料class Invoice:「Invoice(請求書)」という設計図を作る def __init__(self, number, amount, ...):請求書を1枚作るときに、最初に自動で動く処理。材料を受け取る self.number = number受け取った番号を、この請求書の「number」として覚えておく def with_tax(self):請求書に「税込にして」と頼むための処理を作る return self.amount * (100 + self.rate) // 100この請求書の金額と税率から、税込の金額を返す日本語にすると
self.number のように、請求書が覚えているデータを属性、with_tax のように、請求書に頼める処理をメソッドと呼びます。メソッドの最初にある self は、「自分自身」のことです。inv.with_tax() と呼ぶと、inv が self として自動で渡されます。
self が「自分自身」であることは、self を自分で渡しても同じ結果になることで確かめられます。
▶ 実行を押すと、ここに結果が出ます
変えて、試す
① 請求書を何枚も作って、集計する。 作った請求書をリストに入れれば、基礎編の for や、Lesson 01 の内包表記で集計できます。未入金(または不足)の請求書を取り出してみます。(入金額は、payments.csv の内容に合わせています)
▶ 実行を押すと、ここに結果が出ます
② 属性を書き換える。表示を整える。 属性は、inv.paid = 231000 のように書き換えられます。また、クラスをそのまま print すると、<__main__.Invoice object at 0x7f...> のような読めない表示になります。__repr__ というメソッドを作ると、表示する文章を決められます。
▶ 実行を押すと、ここに結果が出ます
不足の1,000円が入金されて、残高が 0 になりました。
③ self を書き忘れる。 メソッドの1つ目の self を書き忘れると、エラーになります。
▶ 実行を押すと、ここに結果が出ます
TypeError: Invoice.with_tax() takes 0 positional arguments but 1 was given と出ます。「材料を0個受け取る作りなのに、1個渡された」という意味で、この「1個」が、自動で渡される self です。メソッドには、必ず最初に self を書きます。
自分で書く
お題① 経費1件を表す Expense クラスに、メソッド needs_receipt を足してください。金額が5,000円以上なら True、そうでなければ False を返します。(5,000円は、この回だけの仮のルールです。実際の基準は、社内の規程に従います)
▶ 実行を押すと、ここに結果が出ます
ヒントを見る
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円なら "未入金" です。
▶ 実行を押すと、ここに結果が出ます
ヒントを見る
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])仕事ならどう使う?
理解チェックinv = Invoice("INV-2025-0004", 210000) の inv を、何と呼びますか?
理解チェックメソッドの中の self は、何を表しているでしょう?