Việc triển khai các giao diện với các lớp cơ sở trừu tượng đơn giản hơn nhiều trong Python 3 hiện đại và chúng phục vụ mục đích như một hợp đồng giao diện cho các tiện ích mở rộng của trình cắm thêm.
Tạo giao diện / lớp cơ sở trừu tượng:
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)
Tạo một lớp con bình thường và ghi đè tất cả các phương thức trừu tượng:
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)
Bạn có thể tùy chọn có triển khai chung trong các phương thức trừu tượng như trong create_sale_invoice()
, gọi nó super()
một cách rõ ràng trong lớp con như trên.
Khởi tạo một lớp con không thực hiện tất cả các phương thức trừu tượng đều thất bại:
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
Bạn cũng có thể có các thuộc tính trừu tượng, phương thức tĩnh và lớp bằng cách kết hợp các chú thích tương ứng với @abstractmethod
.
Các lớp cơ sở trừu tượng là tuyệt vời để thực hiện các hệ thống dựa trên plugin. Tất cả các lớp con được nhập của một lớp đều có thể truy cập thông qua __subclasses__()
, vì vậy nếu bạn tải tất cả các lớp từ thư mục plugin importlib.import_module()
và nếu chúng phân lớp lớp cơ sở, bạn có quyền truy cập trực tiếp vào chúng thông qua __subclasses__()
và bạn có thể chắc chắn rằng hợp đồng giao diện được thi hành cho tất cả chúng trong thời gian khởi tạo.
Đây là cách thực hiện tải plugin cho AccountingSystem
ví dụ trên:
...
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
Sau đó, bạn có thể truy cập đối tượng plugin hệ thống kế toán thông qua AccountingSystem
lớp:
>>> accountingsystem = AccountingSystem.instance()
(Lấy cảm hứng từ bài đăng PyMOTW-3 này .)