Mô-đun này cung cấp cơ sở hạ tầng để xác định [ABC] bằng Python, như được nêu trong PEP 3119; . [Xem thêm PEP 3141 và mô-đun liên quan đến phân cấp loại cho các số dựa trên ABC. ]
Mô-đun này có một số lớp cụ thể bắt nguồn từ ABC; . Ngoài ra, mô hình con có một số ABC có thể được sử dụng để kiểm tra xem một lớp hoặc cá thể có cung cấp một giao diện cụ thể hay không, ví dụ: nếu nó có thể băm được hoặc nếu nó là một ánh xạ
Mô-đun này cung cấp siêu dữ liệu để xác định ABC và một lớp trợ giúp để xác định các ABC khác thông qua kế thừa
lớp abc. ABCMột lớp trợ giúp có siêu dữ liệu của nó. 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 đơn giản xuất phát từ việc tránh sử dụng siêu dữ liệu đôi khi gây nhầm lẫn, ví dụ
from abc import ABC class MyABC[ABC]: pass
Lưu ý rằng loại is still , do đó việc kế thừa từ 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 siêu dữ liệu và sử dụng trực tiếp, ví dụ:
from abc import ABCMeta class MyABC[metaclass=ABCMeta]: pass
Mới trong phiên bản 3. 4
lớp abc. ABCMetaSiêu dữ liệu để xác định 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ác lớp dựng sẵn] và các ABC không liên quan dưới dạng “các lớp con ảo” – những lớp con này và lớp con của chúng sẽ được coi là các lớp con của ABC đăng ký bởi chức năng tích hợp, nhưng ABC đăng ký sẽ không hiển thị .
Các lớp được tạo bằng siêu dữ liệu có phương thức sau
đăng ký[lớp con]Đăng ký lớp con dưới dạng “lớp con ảo” của ABC này. Ví dụ
from abc import ABC class MyABC[ABC]: pass MyABC.register[tuple] assert issubclass[tuple, MyABC] assert isinstance[[], MyABC]
Đã thay đổi trong phiên bản 3. 3. Trả về lớp con đã đăng ký, để cho phép sử dụng làm 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 , bạn có thể sử dụng chức năng.
Bạn cũng có thể ghi đè phương thức này trong một lớp cơ sở trừu tượng
__subclasshook__[lớp con][Phải được định nghĩa là một phương thức lớp. ]
Kiểm tra xem lớp con có được coi là lớp con của ABC này 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
from abc import ABC class MyABC[ABC]: pass MyABC.register[tuple] assert issubclass[tuple, MyABC] assert isinstance[[], MyABC]8 mà không cần gọi đế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
class Foo: def __getitem__[self, index]: ... def __len__[self]: ... def get_iterator[self]: return iter[self] class MyIterable[ABC]: @abstractmethod def __iter__[self]: while False: yield None def get_iterator[self]: return self.__iter__[] @classmethod def __subclasshook__[cls, C]: if cls is MyIterable: if any["__iter__" in B.__dict__ for B in C.__mro__]: return True return NotImplemented MyIterable.register[Foo]0 của ABC. ]
Phương pháp này sẽ trả về
class Foo: def __getitem__[self, index]: ... def __len__[self]: ... def get_iterator[self]: return iter[self] class MyIterable[ABC]: @abstractmethod def __iter__[self]: while False: yield None def get_iterator[self]: return self.__iter__[] @classmethod def __subclasshook__[cls, C]: if cls is MyIterable: if any["__iter__" in B.__dict__ for B in C.__mro__]: return True return NotImplemented MyIterable.register[Foo]1,
class Foo: def __getitem__[self, index]: ... def __len__[self]: ... def get_iterator[self]: return iter[self] class MyIterable[ABC]: @abstractmethod def __iter__[self]: while False: yield None def get_iterator[self]: return self.__iter__[] @classmethod def __subclasshook__[cls, C]: if cls is MyIterable: if any["__iter__" in B.__dict__ for B in C.__mro__]: return True return NotImplemented MyIterable.register[Foo]2 hoặc
class Foo: def __getitem__[self, index]: ... def __len__[self]: ... def get_iterator[self]: return iter[self] class MyIterable[ABC]: @abstractmethod def __iter__[self]: while False: yield None def get_iterator[self]: return self.__iter__[] @classmethod def __subclasshook__[cls, C]: if cls is MyIterable: if any["__iter__" in B.__dict__ for B in C.__mro__]: return True return NotImplemented MyIterable.register[Foo]3. Nếu nó trả về
class Foo: def __getitem__[self, index]: ... def __len__[self]: ... def get_iterator[self]: return iter[self] class MyIterable[ABC]: @abstractmethod def __iter__[self]: while False: yield None def get_iterator[self]: return self.__iter__[] @classmethod def __subclasshook__[cls, C]: if cls is MyIterable: if any["__iter__" in B.__dict__ for B in C.__mro__]: return True return NotImplemented MyIterable.register[Foo]1, lớp con được coi là lớp con của ABC này. Nếu nó trả về
class Foo: def __getitem__[self, index]: ... def __len__[self]: ... def get_iterator[self]: return iter[self] class MyIterable[ABC]: @abstractmethod def __iter__[self]: while False: yield None def get_iterator[self]: return self.__iter__[] @classmethod def __subclasshook__[cls, C]: if cls is MyIterable: if any["__iter__" in B.__dict__ for B in C.__mro__]: return True return NotImplemented MyIterable.register[Foo]2, lớp con không được coi là lớp con của ABC này, ngay cả khi nó thường là một. Nếu nó trả về
class Foo: def __getitem__[self, index]: ... def __len__[self]: ... def get_iterator[self]: return iter[self] class MyIterable[ABC]: @abstractmethod def __iter__[self]: while False: yield None def get_iterator[self]: return self.__iter__[] @classmethod def __subclasshook__[cls, C]: if cls is MyIterable: if any["__iter__" in B.__dict__ for B in C.__mro__]: return True return NotImplemented MyIterable.register[Foo]3, thì việc kiểm tra phân lớp đượ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 Định nghĩa ABC
class Foo: def __getitem__[self, index]: ... def __len__[self]: ... def get_iterator[self]: return iter[self] class MyIterable[ABC]: @abstractmethod def __iter__[self]: while False: yield None def get_iterator[self]: return self.__iter__[] @classmethod def __subclasshook__[cls, C]: if cls is MyIterable: if any["__iter__" in B.__dict__ for B in C.__mro__]: return True return NotImplemented MyIterable.register[Foo]
ABC
class Foo: def __getitem__[self, index]: ... def __len__[self]: ... def get_iterator[self]: return iter[self] class MyIterable[ABC]: @abstractmethod def __iter__[self]: while False: yield None def get_iterator[self]: return self.__iter__[] @classmethod def __subclasshook__[cls, C]: if cls is MyIterable: if any["__iter__" in B.__dict__ for B in C.__mro__]: return True return NotImplemented MyIterable.register[Foo]7 định nghĩa phương thức lặp tiêu chuẩn, , 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
class Foo: def __getitem__[self, index]: ... def __len__[self]: ... def get_iterator[self]: return iter[self] class MyIterable[ABC]: @abstractmethod def __iter__[self]: while False: yield None def get_iterator[self]: return self.__iter__[] @classmethod def __subclasshook__[cls, C]: if cls is MyIterable: if any["__iter__" in B.__dict__ for B in C.__mro__]: return True return NotImplemented MyIterable.register[Foo]9 cũng là một phần của lớp cơ sở trừu tượng
class Foo: def __getitem__[self, index]: ... def __len__[self]: ... def get_iterator[self]: return iter[self] class MyIterable[ABC]: @abstractmethod def __iter__[self]: while False: yield None def get_iterator[self]: return self.__iter__[] @classmethod def __subclasshook__[cls, C]: if cls is MyIterable: if any["__iter__" in B.__dict__ for B in C.__mro__]: return True return NotImplemented MyIterable.register[Foo]7, nhưng nó không cần phải được ghi đè trong các lớp dẫn xuất không trừu tượng
Phương thức lớp được định nghĩa ở đây nói rằng bất kỳ lớp nào có một phương thức trong nó [hoặc trong phương thức của một trong các lớp cơ sở của nó, được truy cập thông qua danh sách] cũng được coi là một
class Foo: def __getitem__[self, index]: ... def __len__[self]: ... def get_iterator[self]: return iter[self] class MyIterable[ABC]: @abstractmethod def __iter__[self]: while False: yield None def get_iterator[self]: return self.__iter__[] @classmethod def __subclasshook__[cls, C]: if cls is MyIterable: if any["__iter__" in B.__dict__ for B in C.__mro__]: return True return NotImplemented MyIterable.register[Foo]7
Cuối cùng, dòng cuối cùng biến
class 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[self]: ... @my_abstract_property.setter @abstractmethod def my_abstract_property[self, val]: ... @abstractmethod def _get_x[self]: ... @abstractmethod def _set_x[self, val]: ... x = property[_get_x, _set_x]6 thành một lớp con ảo của
class Foo: def __getitem__[self, index]: ... def __len__[self]: ... def get_iterator[self]: return iter[self] class MyIterable[ABC]: @abstractmethod def __iter__[self]: while False: yield None def get_iterator[self]: return self.__iter__[] @classmethod def __subclasshook__[cls, C]: if cls is MyIterable: if any["__iter__" in B.__dict__ for B in C.__mro__]: return True return NotImplemented MyIterable.register[Foo]7, mặc dù nó không định nghĩa một phương thức [nó sử dụng giao thức lặp kiểu cũ, được xác định theo thuật ngữ của
class 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[self]: ... @my_abstract_property.setter @abstractmethod def my_abstract_property[self, val]: ... @abstractmethod def _get_x[self]: ... @abstractmethod def _set_x[self, val]: ... x = property[_get_x, _set_x]9 và
class Descriptor: ... @property def __isabstractmethod__[self]: return any[getattr[f, '__isabstractmethod__', False] for f in [self._fget, self._fset, self._fdel]]0]. Lưu ý rằng điều này sẽ không cung cấp
class Descriptor: ... @property def __isabstractmethod__[self]: return any[getattr[f, '__isabstractmethod__', False] for f in [self._fget, self._fset, self._fdel]]1 như một phương pháp của
class 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[self]: ... @my_abstract_property.setter @abstractmethod def my_abstract_property[self, val]: ... @abstractmethod def _get_x[self]: ... @abstractmethod def _set_x[self, val]: ... x = property[_get_x, _set_x]6, vì vậy nó được cung cấp riêng
Mô-đun này cũng cung cấp trình trang trí sau
@abc. phương pháp trừu tượngMột trình trang trí chỉ ra các phương thức trừu tượng
Sử dụng trình trang trí này yêu cầu siêu dữ liệu của lớp hoặc được bắt nguồn từ nó. Một lớp có siêu dữ liệu bắt nguồn từ 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. 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ả
Tự động thêm 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 hàm. Điều duy nhất ảnh hưởng đến các lớp con có nguồn gốc bằng cách sử dụng kế thừa thông thường;
Khi đượ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 bộ trang trí trong cùng, như thể hiện trong các ví dụ sử dụng sau
class 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[self]: ... @my_abstract_property.setter @abstractmethod def my_abstract_property[self, val]: ... @abstractmethod def _get_x[self]: ... @abstractmethod def _set_x[self, val]: ... x = property[_get_x, _set_x]
Để tương tác chính xác với bộ máy của lớp cơ sở trừu tượng, bộ mô tả phải xác định chính nó là trừu tượng bằng cách sử dụng
class C[ABC]: @classmethod @abstractmethod def my_abstract_classmethod[cls, arg]: ...1. Nói chung, thuộc tính này phải là
class Foo: def __getitem__[self, index]: ... def __len__[self]: ... def get_iterator[self]: return iter[self] class MyIterable[ABC]: @abstractmethod def __iter__[self]: while False: yield None def get_iterator[self]: return self.__iter__[] @classmethod def __subclasshook__[cls, C]: if cls is MyIterable: if any["__iter__" in B.__dict__ for B in C.__mro__]: return True return NotImplemented MyIterable.register[Foo]1 nếu bất kỳ phương thức nào được sử dụng để soạn bộ mô tả là trừu tượng. Ví dụ: phần mềm tích hợp sẵn của Python thực hiện tương đương với
class Descriptor: ... @property def __isabstractmethod__[self]: return any[getattr[f, '__isabstractmethod__', False] for f in [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ó một triển khai. Việc triển khai này có thể được gọi thông qua cơ chế từ lớp ghi đè lên nó. Điều này có thể hữu ích như một điểm cuối cho siêu lệnh gọi trong khung sử dụng đa kế thừa hợp tác
Mô-đun này cũng hỗ trợ các trình trang trí kế thừa sau
@abc. phương pháp lớp trừu tượngMới trong phiên bản 3. 2
Không dùng nữa kể từ phiên bản 3. 3. Hiện có thể sử dụng with , làm cho công cụ trang trí này trở nên dư thừa.
Một lớp con của 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ư
Trường hợp đặc biệt này không được dùng nữa, vì trình trang trí hiện được xác định chính xác là trừu tượng khi được áp dụng cho một phương thức trừu tượng
class C[ABC]: @classmethod @abstractmethod def my_abstract_classmethod[cls, arg]: ...@abc. phương pháp tĩnh trừu tượng
Mới trong phiên bản 3. 2
Không dùng nữa kể từ phiên bản 3. 3. Hiện có thể sử dụng with , làm cho công cụ trang trí này trở nên dư thừa.
Một lớp con của tích hợp sẵn, biểu thị một phương pháp tĩnh trừu tượng. Nếu không thì nó tương tự như
Trường hợp đặc biệt này không được dùng nữa, vì trình trang trí hiện được xác định chính xác là trừu tượng khi được áp dụng cho một phương thức trừu tượng
class C[ABC]: @staticmethod @abstractmethod def my_abstract_staticmethod[arg]: ...@abc. tài sản trừu tượng
Không dùng nữa kể từ phiên bản 3. 3. Hiện tại có thể sử dụng ,
class C[ABC]: @staticmethod @abstractmethod def my_abstract_staticmethod[arg]: ...7,
class C[ABC]: @staticmethod @abstractmethod def my_abstract_staticmethod[arg]: ...8 và
class C[ABC]: @staticmethod @abstractmethod def my_abstract_staticmethod[arg]: ...9 với , làm cho công cụ trang trí này trở nên dư thừa.
Một lớp con của tích hợp sẵn, 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í hiện được xác định chính xác là trừu tượng khi được áp dụng cho một phương thức trừu tượng
class C[ABC]: @property @abstractmethod def my_abstract_property[self]: ...
Ví dụ trên định nghĩa thuộc tính chỉ đọc;
class C[ABC]: @property def x[self]: ... @x.setter @abstractmethod def x[self, val]: ...
Nếu chỉ một số thành phần là trừu tượng, thì chỉ những thành phần đó cần được cập nhật để tạo một thuộc tính cụ thể trong một lớp con
from abc import ABCMeta class MyABC[metaclass=ABCMeta]: pass0
Mô-đun này cũng cung cấp các chức năng sau
abc. get_cache_token[]Trả về mã thông báo bộ nhớ cache 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] 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 với mọi cuộc gọi đến trên bất kỳ ABC nào
Mới trong phiên bản 3. 4
abc. update_abstractmethods[cls]Hàm tính toán lại trạng thái trừu tượng của lớp trừu tượng. Hàm này nên đượ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, chức năng này nên được gọi từ bên trong một trình trang trí lớp
Trả về cls, để cho phép sử dụng làm công cụ trang trí lớp
Nếu cls không phải là một thể hiện của , thì không có gì
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