การนำอินเตอร์เฟสไปใช้กับคลาสฐานนามธรรมนั้นง่ายกว่ามากใน Python 3 ที่ทันสมัยและใช้เป็นวัตถุประสงค์ในการทำสัญญาเป็นส่วนต่อประสานสำหรับส่วนขยายปลั๊กอิน
สร้างอินเทอร์เฟซ / นามธรรมคลาสพื้นฐาน:
from abc import ABC, abstractmethod
class AccountingSystem(ABC):
@abstractmethod
def create_purchase_invoice(self, purchase):
pass
@abstractmethod
def create_sale_invoice(self, sale):
log.debug('Creating sale invoice', sale)
สร้างคลาสย่อยปกติและแทนที่เมธอด abstract ทั้งหมด:
class GizmoAccountingSystem(AccountingSystem):
def create_purchase_invoice(self, purchase):
submit_to_gizmo_purchase_service(purchase)
def create_sale_invoice(self, sale):
super().create_sale_invoice(sale)
submit_to_gizmo_sale_service(sale)
คุณสามารถเลือกที่จะมีการนำไปใช้ทั่วไปในเมธอด abstract ดังเช่นในcreate_sale_invoice()
เรียกมันsuper()
อย่างชัดเจนในคลาสย่อยดังกล่าวข้างต้น
การสร้างอินสแตนซ์ของคลาสย่อยที่ไม่ใช้เมธอด abstract ทั้งหมดล้มเหลว:
class IncompleteAccountingSystem(AccountingSystem):
pass
>>> accounting = IncompleteAccountingSystem()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class IncompleteAccountingSystem with abstract methods
create_purchase_invoice, create_sale_invoice
นอกจากนี้คุณยังสามารถมีคุณสมบัตินามธรรมวิธีคงที่และวิธีการเรียนโดยการรวมคำอธิบายประกอบที่เกี่ยวข้องกับ @abstractmethod
นอกจากนี้คุณยังสามารถมีคุณสมบัตินามธรรมแบบคงที่และวิธีการเรียนโดยการรวมคำอธิบายประกอบที่สอดคล้องกับ
คลาสพื้นฐานที่เป็นนามธรรมนั้นยอดเยี่ยมสำหรับการติดตั้งระบบที่ใช้ปลั๊กอิน คลาสย่อยที่นำเข้าทั้งหมดของคลาสนั้นสามารถเข้าถึงได้ผ่านทาง__subclasses__()
ดังนั้นหากคุณโหลดคลาสทั้งหมดจากไดเรกทอรีปลั๊กอินด้วยimportlib.import_module()
และหากพวกเขาคลาสย่อยคลาสฐานคุณมีการเข้าถึงโดยตรงกับคลาสเหล่านั้นผ่านทาง__subclasses__()
และคุณสามารถมั่นใจได้ว่าสัญญาอินเทอร์เฟซ พวกเขาในระหว่างการเริ่ม
นี่คือการใช้งานการโหลดปลั๊กอินสำหรับAccountingSystem
ตัวอย่างด้านบน:
...
from importlib import import_module
class AccountingSystem(ABC):
...
_instance = None
@classmethod
def instance(cls):
if not cls._instance:
module_name = settings.ACCOUNTING_SYSTEM_MODULE_NAME
import_module(module_name)
subclasses = cls.__subclasses__()
if len(subclasses) > 1:
raise InvalidAccountingSystemError('More than one '
f'accounting module: {subclasses}')
if not subclasses or module_name not in str(subclasses[0]):
raise InvalidAccountingSystemError('Accounting module '
f'{module_name} does not exist or does not '
'subclass AccountingSystem')
cls._instance = subclasses[0]()
return cls._instance
จากนั้นคุณสามารถเข้าถึงวัตถุปลั๊กอินระบบบัญชีผ่านAccountingSystem
คลาสได้
>>> accountingsystem = AccountingSystem.instance()
(แรงบันดาลใจจากโพสต์ PyMOTW-3 )