abc --- Các lớp cơ sở trừu tượng

Source code: Lib/abc.py


Mô-đun này cung cấp cơ sở hạ tầng để xác định abstract base classes (ABC) trong Python, như được nêu trong PEP 3119; xem PEP để biết lý do tại sao điều này được thêm vào Python. (Xem thêm PEP 3141 và mô-đun numbers về phân cấp loại cho các số dựa trên ABC.)

Mô-đun collections có một số lớp cụ thể xuất phát từ ABC; tất nhiên những điều này có thể được rút ra thêm. Ngoài ra, mô-đun con collections.abc có một số ABC có thể được sử dụng để kiểm tra xem một lớp hoặc phiên bản có cung cấp một giao diện cụ thể hay không, chẳng hạn như đó là hashable hay mapping.

Mô-đun này cung cấp siêu dữ liệu ABCMeta để xác định ABC và lớp trợ giúp ABC để xác định ABC thông qua tính kế thừa:

class abc.ABC

Một lớp trợ giúp có siêu dữ liệu là ABCMeta. Với lớp này, một lớp cơ sở trừu tượng có thể được tạo bằng cách bắt nguồn từ ABC để tránh việc sử dụng siêu dữ liệu đôi khi gây nhầm lẫn, ví dụ:

từ abc nhập ABC

lớp MyABC(ABC):
    vượt qua

Lưu ý rằng loại ABC vẫn là ABCMeta, do đó việc kế thừa từ ABC yêu cầu các biện pháp phòng ngừa thông thường liên quan đến việc sử dụng siêu dữ liệu, vì nhiều kế thừa có thể dẫn đến xung đột siêu dữ liệu. Người ta cũng có thể định nghĩa một lớp cơ sở trừu tượng bằng cách chuyển từ khóa metaclass và sử dụng trực tiếp ABCMeta, ví dụ:

từ abc nhập ABCMeta

lớp MyABC(metaclass=ABCMeta):
    vượt qua

Added in version 3.4.

class abc.ABCMeta

Siêu dữ liệu để xác định các Lớp cơ sở trừu tượng (ABC).

Sử dụng siêu dữ liệu này để tạo ABC. Một ABC có thể được phân lớp trực tiếp và sau đó hoạt động như một lớp hỗn hợp. Bạn cũng có thể đăng ký các lớp cụ thể không liên quan (thậm chí các lớp dựng sẵn) và các ABC không liên quan làm "lớp con ảo" -- những lớp này và lớp con của chúng sẽ được coi là lớp con của việc đăng ký ABC bởi hàm issubclass() tích hợp, nhưng việc đăng ký ABC sẽ không hiển thị trong MRO (Thứ tự phân giải phương thức) của chúng cũng như việc triển khai phương thức được xác định bởi ABC đăng ký sẽ không thể gọi được (thậm chí không thông qua super()). [1]

Các lớp được tạo bằng siêu dữ liệu ABCMeta có phương thức sau:

register(subclass)

Đăng ký subclass làm "lớp con ảo" của ABC này. Ví dụ:

từ abc nhập ABC

lớp MyABC(ABC):
    vượt qua

MyABC.register(tuple)

khẳng định issubclass(tuple, MyABC)
khẳng định isinstance((), MyABC)

Thay đổi trong phiên bản 3.3: Trả về lớp con đã đăng ký, để cho phép sử dụng như một công cụ trang trí lớp.

Thay đổi trong phiên bản 3.4: Để phát hiện các cuộc gọi đến register(), bạn có thể sử dụng chức năng get_cache_token().

Bạn cũng có thể ghi đè phương thức này trong lớp cơ sở trừu tượng:

__subclasshook__(subclass)

(Phải được định nghĩa là một phương thức lớp.)

Kiểm tra xem subclass có được coi là lớp con của ABC này hay không. Điều này có nghĩa là bạn có thể tùy chỉnh thêm hành vi của issubclass() mà không cần phải gọi register() trên mỗi lớp mà bạn muốn coi là lớp con của ABC. (Phương thức lớp này được gọi từ phương thức __subclasscheck__() của ABC.)

Phương thức này sẽ trả về True, False hoặc NotImplemented. Nếu nó trả về True thì subclass được coi là lớp con của ABC này. Nếu nó trả về False, subclass không được coi là lớp con của ABC này, ngay cả khi nó thường là một lớp con. Nếu nó trả về NotImplemented, việc kiểm tra lớp con sẽ được tiếp tục với cơ chế thông thường.

Để minh họa các khái niệm này, hãy xem ví dụ này về định nghĩa ABC:

lớp Foo:
    def __getitem__(tự, chỉ mục):
        ...
    chắc chắn __len__(tự):
        ...
    def get_iterator(self):
        trả về iter(self)

lớp MyIterable(ABC):

    @abstractmethod
    chắc chắn __iter__(tự):
        trong khi sai:
            năng suất Không 

    def get_iterator(self):
        tự trả về.__iter__()

    @classmethod
    def __subclasshook__(cls, C):
        nếu cls  MyIterable:
            nếu ("__iter__" trong B.__dict__ cho B trong C.__mro__):
                trả về Đúng
        trả về Chưa thực hiện

MyIterable.register(Foo)

ABC MyIterable định nghĩa phương thức lặp tiêu chuẩn, __iter__(), là một phương thức trừu tượng. Việc triển khai được đưa ra ở đây vẫn có thể được gọi từ các lớp con. Phương thức get_iterator() cũng là một phần của lớp cơ sở trừu tượng MyIterable, nhưng nó không bị ghi đè trong các lớp dẫn xuất không trừu tượng.

Phương thức lớp __subclasshook__() được định nghĩa ở đây cho biết rằng bất kỳ lớp nào có phương thức __iter__() trong __dict__ của nó (hoặc trong một trong các lớp cơ sở của nó, được truy cập thông qua danh sách __mro__) cũng được coi là MyIterable.

Cuối cùng, dòng cuối cùng biến Foo thành một lớp con ảo của MyIterable, mặc dù nó không định nghĩa phương thức __iter__() (nó sử dụng giao thức lặp kiểu cũ, được định nghĩa theo __len__()__getitem__()). Lưu ý rằng điều này sẽ không cung cấp get_iterator như một phương thức của Foo, vì vậy nó được cung cấp riêng.

Mô-đun abc cũng cung cấp công cụ trang trí sau:

@abc.abstractmethod

Một trang trí chỉ ra các phương pháp trừu tượng.

Việc sử dụng trình trang trí này yêu cầu siêu dữ liệu của lớp là ABCMeta hoặc bắt nguồn từ siêu dữ liệu đó. Một lớp có siêu dữ liệu bắt nguồn từ ABCMeta không thể được khởi tạo trừ khi tất cả các phương thức và thuộc tính trừu tượng của nó bị ghi đè. Các phương thức trừu tượng có thể được gọi bằng cách sử dụng bất kỳ cơ chế gọi 'siêu' thông thường nào. abstractmethod() có thể được sử dụng để khai báo các phương thức trừu tượng cho các thuộc tính và bộ mô tả.

Việc thêm động các phương thức trừu tượng vào một lớp hoặc cố gắng sửa đổi trạng thái trừu tượng của một phương thức hoặc lớp sau khi nó được tạo chỉ được hỗ trợ bằng cách sử dụng hàm update_abstractmethods(). Zz001zz chỉ ảnh hưởng đến các lớp con được dẫn xuất bằng cách sử dụng tính kế thừa thông thường; "Các lớp con ảo" được đăng ký bằng phương thức register() của ABC không bị ảnh hưởng.

Khi abstractmethod() được áp dụng kết hợp với các bộ mô tả phương thức khác, nó sẽ được áp dụng làm phần trang trí trong cùng, như trong các ví dụ sử dụng sau:

lớp C (ABC):
    @abstractmethod
    def my_abstract_method(self, arg1):
        ...
    @classmethod
    @abstractmethod
    def my_abstract_classmethod(cls, arg2):
        ...
    @staticmethod
    @abstractmethod
    def my_abstract_staticmethod(arg3):
        ...

    @property
    @abstractmethod
    def my_abstract_property(tự):
        ...
    @my_abstract_property.setter
    @abstractmethod
    def my_abstract_property(self, val):
        ...

    @abstractmethod
    def _get_x(tự):
        ...
    @abstractmethod
    def _set_x(tự, val):
        ...
    x = thuộc tính(_get_x, _set_x)

Để tương tác chính xác với máy móc lớp cơ sở trừu tượng, bộ mô tả phải tự xác định là trừu tượng bằng cách sử dụng __isabstractmethod__. Nói chung, thuộc tính này phải là True nếu bất kỳ phương thức nào được sử dụng để soạn thảo bộ mô tả là trừu tượng. Ví dụ: property tích hợp của Python thực hiện tương đương với

 tả lớp:
    ...
    @property
    def __isabstractmethod__(self):
        trả về bất kỳ(getattr(f, '__isabstractmethod__', False) cho
                   f trong (self._fget, self._fset, self._fdel))

Ghi chú

Không giống như các phương thức trừu tượng của Java, các phương thức trừu tượng này có thể được triển khai. Việc triển khai này có thể được gọi thông qua cơ chế super() từ lớp ghi đè nó. Điều này có thể hữu ích như một điểm cuối cho một siêu lệnh gọi trong một khung sử dụng tính năng đa kế thừa hợp tác.

Mô-đun abc cũng hỗ trợ các trình trang trí cũ sau:

@abc.abstractclassmethod

Added in version 3.2.

Sắp loại bỏ từ phiên bản 3.3: Hiện tại có thể sử dụng classmethod với abstractmethod(), khiến công cụ trang trí này trở nên dư thừa.

Một lớp con của classmethod() tích hợp sẵn, biểu thị một phương thức lớp trừu tượng. Nếu không thì nó tương tự như abstractmethod().

Trường hợp đặc biệt này không được dùng nữa vì trình trang trí classmethod() hiện được xác định chính xác là trừu tượng khi áp dụng cho một phương thức trừu tượng

lớp C (ABC):
    @classmethod
    @abstractmethod
    def my_abstract_classmethod(cls, arg):
        ...
@abc.abstractstaticmethod

Added in version 3.2.

Sắp loại bỏ từ phiên bản 3.3: Hiện tại có thể sử dụng staticmethod với abstractmethod(), khiến công cụ trang trí này trở nên dư thừa.

Một lớp con của staticmethod() tích hợp, biểu thị một phương thức tĩnh trừu tượng. Nếu không thì nó tương tự như abstractmethod().

Trường hợp đặc biệt này không được dùng nữa vì trình trang trí staticmethod() hiện được xác định chính xác là trừu tượng khi áp dụng cho một phương thức trừu tượng

lớp C (ABC):
    @staticmethod
    @abstractmethod
    def my_abstract_staticmethod(arg):
        ...
@abc.abstractproperty

Sắp loại bỏ từ phiên bản 3.3: Hiện tại có thể sử dụng property, property.getter(), property.setter()property.deleter() với abstractmethod(), khiến công cụ trang trí này trở nên dư thừa.

Một lớp con của property() tích hợp, biểu thị một thuộc tính trừu tượng.

Trường hợp đặc biệt này không được dùng nữa vì trình trang trí property() hiện được xác định chính xác là trừu tượng khi áp dụng cho một phương thức trừu tượng

lớp C (ABC):
    @property
    @abstractmethod
    def my_abstract_property(tự):
        ...

Ví dụ trên định nghĩa thuộc tính chỉ đọc; bạn cũng có thể xác định thuộc tính trừu tượng đọc-ghi bằng cách đánh dấu thích hợp một hoặc nhiều phương thức cơ bản là trừu tượng:

lớp C (ABC):
    @property
    def x(tự):
        ...

    @x.setter
    @abstractmethod
    def x(tự, val):
        ...

Nếu chỉ một số thành phần là trừu tượng thì chỉ những thành phần đó mới cần được cập nhật để tạo thuộc tính cụ thể trong lớp con:

lớp D (C):
    @C.x.setter
    def x(tự, val):
        ...

Mô-đun abc cũng cung cấp các chức năng sau:

abc.get_cache_token()

Trả về mã thông báo bộ đệm của lớp cơ sở trừu tượng hiện tại.

Mã thông báo là một đối tượng mờ (hỗ trợ kiểm tra tính bằng nhau) xác định phiên bản hiện tại của bộ đệm lớp cơ sở trừu tượng cho các lớp con ảo. Mã thông báo thay đổi sau mỗi lệnh gọi tới ABCMeta.register() trên bất kỳ ABC nào.

Added in version 3.4.

abc.update_abstractmethods(cls)

Một hàm để tính toán lại trạng thái trừu tượng của một lớp trừu tượng. Hàm này sẽ được gọi nếu các phương thức trừu tượng của một lớp đã được triển khai hoặc thay đổi sau khi nó được tạo. Thông thường, hàm này nên được gọi từ bên trong trình trang trí lớp.

Trả về cls, để cho phép sử dụng như một công cụ trang trí lớp.

Nếu cls không phải là một phiên bản của ABCMeta thì không làm gì cả.

Ghi chú

Hàm này giả định rằng các siêu lớp của cls đã được cập nhật. Nó không cập nhật bất kỳ lớp con nào.

Added in version 3.10.

Chú thích cuối trang