Lớp Python trong tệp riêng

Tất cả các lớp này đều có sẵn trong mô-đun collections và (thực tế là có tổng cộng 25 lớp) được định nghĩa trong mô-đun thư viện tiêu chuẩn trong _collections_abc.py

Có một số vấn đề ở đây mà tôi tin rằng làm cho _collections_abc.py vượt trội hơn so với cấu trúc thư mục giả định thay thế

  • Các tệp này được sắp xếp theo thứ tự bảng chữ cái. Bạn có thể sắp xếp chúng theo những cách khác, nhưng tôi không biết về tính năng sắp xếp tệp theo phụ thuộc ngữ nghĩa. Nguồn mô-đun _collections_abc được tổ chức theo sự phụ thuộc
  • Trong các trường hợp không bệnh lý, cả định nghĩa mô-đun và lớp đều là đơn lẻ, xuất hiện một lần trong bộ nhớ. Sẽ có một ánh xạ phỏng đoán của các mô-đun lên các lớp - làm cho các mô-đun trở nên dư thừa
  • Số lượng tệp ngày càng tăng khiến việc đọc qua các lớp không thuận tiện (trừ khi bạn có một IDE làm cho nó đơn giản) - khiến những người không có công cụ khó truy cập hơn

Bạn có bị ngăn cản việc chia các nhóm lớp thành các mô-đun khác nhau khi bạn thấy điều đó là mong muốn từ góc độ tổ chức và không gian tên không?

Không

Từ Zen of Python , phản ánh triết lý và nguyên tắc mà nó đã phát triển và phát triển

Không gian tên là một ý tưởng tuyệt vời -- hãy làm nhiều hơn thế nữa

Nhưng chúng ta hãy nhớ rằng nó cũng nói

Căn hộ tốt hơn lồng nhau

Python cực kỳ rõ ràng và dễ đọc. Nó khuyến khích bạn đọc nó. Đặt mỗi lớp riêng biệt trong một tệp riêng biệt không khuyến khích đọc. Điều này đi ngược lại triết lý cốt lõi của Python. Nhìn vào cấu trúc của Thư viện tiêu chuẩn, phần lớn các mô-đun là mô-đun tệp đơn, không phải gói. Tôi muốn trình bày với bạn rằng mã Python thành ngữ được viết theo cùng kiểu với lib tiêu chuẩn của CPython

Đây là mã thực tế từ mô-đun lớp cơ sở trừu tượng. Tôi thích sử dụng nó như một tài liệu tham khảo để biểu thị các loại trừu tượng khác nhau trong ngôn ngữ

Bạn có nói rằng mỗi lớp này nên yêu cầu một tệp riêng không?

class Hashable:
    __metaclass__ = ABCMeta

    @abstractmethod
    def __hash__(self):
        return 0

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Hashable:
            try:
                for B in C.__mro__:
                    if "__hash__" in B.__dict__:
                        if B.__dict__["__hash__"]:
                            return True
                        break
            except AttributeError:
                # Old-style class
                if getattr(C, "__hash__", None):
                    return True
        return NotImplemented


class Iterable:
    __metaclass__ = ABCMeta

    @abstractmethod
    def __iter__(self):
        while False:
            yield None

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Iterable:
            if _hasattr(C, "__iter__"):
                return True
        return NotImplemented

Iterable.register(str)


class Iterator(Iterable):

    @abstractmethod
    def next(self):
        'Return the next item from the iterator. When exhausted, raise StopIteration'
        raise StopIteration

    def __iter__(self):
        return self

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Iterator:
            if _hasattr(C, "next") and _hasattr(C, "__iter__"):
                return True
        return NotImplemented


class Sized:
    __metaclass__ = ABCMeta

    @abstractmethod
    def __len__(self):
        return 0

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Sized:
            if _hasattr(C, "__len__"):
                return True
        return NotImplemented


class Container:
    __metaclass__ = ABCMeta

    @abstractmethod
    def __contains__(self, x):
        return False

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Container:
            if _hasattr(C, "__contains__"):
                return True
        return NotImplemented


class Callable:
    __metaclass__ = ABCMeta

    @abstractmethod
    def __call__(self, *args, **kwds):
        return False

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Callable:
            if _hasattr(C, "__call__"):
                return True
        return NotImplemented

Vì vậy, mỗi người nên có tập tin riêng của họ?

tôi hy vọng không

Các tệp này không chỉ là mã - chúng là tài liệu về ngữ nghĩa của Python

Chúng có thể trung bình từ 10 đến 20 dòng. Tại sao tôi phải vào một tệp hoàn toàn riêng biệt để xem 10 dòng mã khác? . Hơn nữa, sẽ có các bản nhập soạn sẵn gần như giống hệt nhau trên mỗi tệp, thêm nhiều dòng mã dự phòng hơn

Tôi thấy khá hữu ích khi biết rằng có một mô-đun duy nhất nơi tôi có thể tìm thấy tất cả các Lớp Cơ sở Trừu tượng này, thay vì phải xem qua danh sách các mô-đun. Xem chúng trong ngữ cảnh với nhau cho phép tôi hiểu rõ hơn về chúng. Khi tôi thấy một Iterator là một Iterable, tôi có thể nhanh chóng xem lại Iterable bao gồm những gì bằng cách liếc lên

Đôi khi tôi có một vài lớp học rất ngắn. Chúng ở trong tệp, ngay cả khi chúng cần phát triển lớn hơn theo thời gian. Đôi khi các mô-đun trưởng thành có hơn 1000 dòng mã. Nhưng ctrl-f rất dễ dàng và một số IDE giúp dễ dàng xem các đường viền của tệp - vì vậy, bất kể tệp lớn đến đâu, bạn có thể nhanh chóng chuyển đến bất kỳ đối tượng hoặc phương thức nào mà bạn đang tìm kiếm

Phần kết luận

Hướng của tôi, trong ngữ cảnh của Python, là thích giữ các định nghĩa lớp có liên quan và giống nhau về mặt ngữ nghĩa trong cùng một tệp. Nếu tệp phát triển quá lớn đến mức trở nên khó sử dụng, thì hãy xem xét tổ chức lại

Tôi có nên đặt các lớp trong các tệp Python riêng biệt không?

Python cực kỳ rõ ràng và dễ đọc. Nó khuyến khích bạn đọc nó. Đặt mỗi lớp riêng biệt vào một tệp riêng biệt không khuyến khích việc đọc . Điều này đi ngược lại triết lý cốt lõi của Python.

Các lớp có nên là các tệp riêng biệt không?

Bạn nên làm như vậy . Bạn có thể dễ dàng tìm thấy lớp nếu bạn đặt tên tệp sau lớp.

Bạn có thể có nhiều lớp Python trong một tệp không?

Mọi thứ trong thư viện Python và các ứng dụng Python khác đều là mô-đun hoặc gói mô-đun. Không có giới hạn về số lượng lớp mà một người có thể đặt trong một tệp hoặc một mô-đun .

Python có phải là một lớp trên mỗi tệp không?

Trong Python có quy tắc một mô-đun=một tệp. Trong Python nếu bạn giới hạn bản thân ở một lớp trên mỗi tệp (điều này không bị cấm trong Python), bạn có thể nhận được một số lượng lớn tệp nhỏ – không dễ theo dõi. Vì vậy, tùy thuộc vào tình huống và sự thuận tiện người ta có thể có một hoặc nhiều lớp cho mỗi tệp trong Python .