Tại sao phương pháp trừu tượng được sử dụng trong python?

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. ABC

Mộ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. ABCMeta

Siê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ượng

Mộ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ượ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 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]:
    pass
0

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

Tại sao bạn sẽ sử dụng một phương pháp trừu tượng?

Trong bất kỳ ngôn ngữ lập trình nào, tính trừu tượng có nghĩa là ẩn các chi tiết không liên quan khỏi người dùng để chỉ tập trung vào các chi tiết thiết yếu nhằm tăng hiệu quả do đó giảm độ phức tạp . Trong Java, sự trừu tượng đạt được bằng cách sử dụng các lớp và phương thức trừu tượng.

Phương pháp trừu tượng trong Python là gì?

Một phương thức trừu tượng là một phương thức được khai báo nhưng không chứa phần triển khai . Các lớp trừu tượng có thể không được khởi tạo và các phương thức trừu tượng của nó phải được thực hiện bởi các lớp con của nó.

Chủ Đề