Menu
CoddyTech

抽象クラスとメソッド

CoddyのPythonジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 25/64。

抽象クラスとは、直接インスタンス化できず、サブクラスで実装しなければならない抽象メソッドを含むクラスです。

書式にたとえて考えてみましょう:抽象クラスは、必須項目(抽象メソッド)と任意項目(具象メソッド)がある、必ず記入しなければならない書式のようなものです。書式そのものを提出することはできず、まずすべての必須項目を記入しなければなりません。同様に、サブクラスですべての抽象メソッドが実装されるまでは、抽象クラスのインスタンスを作成できません。

抽象クラスを作成するには、abc モジュールをインポートします。

from abc import ABC, abstractmethod

抽象メソッドを持つ抽象クラスを作成します。

class Shape(ABC):
    @abstractmethod
    def area(self):
        pass
    
    @abstractmethod
    def perimeter(self):
        pass
    
    def describe(self):
        return "This is a shape"  # 具象メソッド(実装がある)

@abstractmethodデコレーターは、サブクラスで必ず実装しなければならないメソッドを示します。これらはフォームの「必須フィールド」です。describe()のような通常のメソッドには実装を持たせることができ、そのまま継承されます。これらは「事前入力済みフィールド」です。

抽象クラスを使う理由は? 抽象クラスは契約を強制します。Shape クラスを作るということは、「すべての図形は面積と周囲の長さを計算できなければならない」と宣言することです。これにより、重要なメソッドの実装を忘れてしまうことで発生するバグを防げます。

抽象クラスのインスタンスを作成してみましょう。

# これによりエラーが発生します:
# shape = Shape()  # TypeError: 抽象クラスはインスタンス化できません

このエラーは意図的なものです。空のフォームを送信しようとするようなものです。Pythonは「必須項目(areaメソッドとperimeterメソッド)がまだ入力されていません!」と言っています。

すべての抽象メソッドを実装する具象サブクラスを作成します。

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
    
    def area(self):
        return 3.14 * self.radius ** 2
    
    def perimeter(self):
        return 2 * 3.14 * self.radius

これで「必要なフィールドをすべて埋めた」ことになります。area()とperimeter()の両方を実装しました。Circleクラスは、インスタンス化できる完全な具象クラスになりました。

これで、具象クラスのインスタンスを作成できます。

circle = Circle(5)
print(circle.area())
print(circle.perimeter())
print(circle.describe())  # 継承された具象メソッド

別の具象サブクラスを作成します。

class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height
    
    def area(self):
        return self.width  self.height
    
    def perimeter(self):
        return 2 * (self.width + self.height)

rectangle = Rectangle(4, 6)
print(rectangle.area())
print(rectangle.perimeter())

出力:

78.5
31.400000000000002
This is a shape
24
20

抽象クラスは、サブクラスが従うべき契約を定義します。ABCと@abstractmethodを使って抽象クラスを作成します。サブクラスはすべての抽象メソッドを実装する必要があり、そうしなければそのサブクラスも抽象クラスになります。これにより一貫性が保たれ、不完全な実装を防げます。

challenge icon

チャレンジ

中級

このチャレンジでは、決済処理システムを実装します。

次のファイルの実装を完成させてください。

  • paymentmethod.py - 検証ロジックを備えた抽象基底クラス
  • creditcard.py - クレジットカード決済の実装
  • paypal.py - PayPal決済の実装

各ファイルのTODOコメントに従って、必要な機能を実装してください。コメントに沿って、抽象メソッドの作成、具象サブクラスの実装、ファイル間の適切なインポート関係の設定を順を追って進められます。

driver.pyファイルには、さまざまな決済シナリオを処理し、それぞれの決済方法に応じた詳細を表示することで、実装が正しく動作するかを検証するテストケースが含まれています。

自分で試してみよう

from creditcard import CreditCard
from paypal import PayPal

# 実装をテストする - このテストコードは変更しないでください
cc = CreditCard("1234567890123456")
pp = PayPal("user@example.com")

# 有効な支払いを処理する
if cc.validate(100):
    print(cc.process_payment(100))
    print(cc.payment_details())

if pp.validate(200):
    print(pp.process_payment(200))
    print(pp.payment_details())

# 無効な金額を試す
if not pp.validate(0):
    print("Invalid payment amount")

# コメントを解除すると、これはエラーになります:
# pm = PaymentMethod()  # 抽象クラスはインスタンス化できない
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Pythonオンラインコンパイラ