抽象クラスとメソッド
CoddyのPythonジャーニー「Object Oriented Programming」セクションの一部 — レッスン 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 を使用します。サブクラスはすべての抽象メソッドを実装しなければならず、そうしない場合はそのサブクラスも抽象クラスになります。これにより一貫性が確保され、不完全な実装を防ぐことができます。
チャレンジ
中級このチャレンジでは、支払い処理システムを実装します。
以下のファイルの実装を完了させる必要があります:
paymentmethod.py- バリデーションロジックを持つ抽象基底クラスcreditcard.py- クレジットカード支払いの実装paypal.py- PayPal支払いの実装
各ファイルの TODO コメントに従って、必要な機能を実装してください。コメントは、抽象メソッドの作成、具体的なサブクラスの実装、およびファイル間の適切なインポート関係の確立をステップバイステップでガイドします。
driver.py ファイルには、実装が正しく動作することを確認するためのテストケースが含まれており、さまざまな支払いシナリオを処理し、各支払い方法の適切な詳細を表示します。
チートシート
抽象クラスは直接インスタンス化することはできず、サブクラスで実装しなければならない抽象メソッドを含みます。
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デコレータは、サブクラスで実装しなければならないメソッドをマークします。通常のメソッドは実装を持つことができます。
抽象クラスはインスタンス化できません:
# これはエラーを引き起こします:
# shape = Shape() # TypeError: Can't instantiate abstract classすべての抽象メソッドを実装する具体的なサブクラスを作成します:
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
circle = Circle(5)
print(circle.area()) # 78.5
print(circle.describe()) # 継承された具体的なメソッド重要なポイント:抽象クラスは、サブクラスが従わなければならないテンプレートを定義します。サブクラスはすべての抽象メソッドを実装しなければならず、そうしない場合はそのサブクラスも抽象クラスになります。
自分で試してみよう
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() # 抽象クラスはインスタンス化できませんこのレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。