Câu hỏi Có một lợi ích để xác định một lớp bên trong một lớp khác trong Python?


Những gì tôi đang nói ở đây là các lớp lồng nhau. Về cơ bản, tôi có hai lớp mà tôi đang làm mẫu. Một lớp DownloadManager và một lớp DownloadThread. Khái niệm OOP rõ ràng ở đây là thành phần. Tuy nhiên, bố cục không nhất thiết có nghĩa là làm tổ, phải không?

Tôi có mã trông giống như thế này:

class DownloadThread:
    def foo(self):
        pass

class DownloadManager():
    def __init__(self):
        dwld_threads = []
    def create_new_thread():
        dwld_threads.append(DownloadThread())

Nhưng bây giờ tôi tự hỏi nếu có một tình huống mà làm tổ sẽ tốt hơn. Cái gì đó như:

class DownloadManager():
    class DownloadThread:
        def foo(self):
            pass
    def __init__(self):
        dwld_threads = []
    def create_new_thread():
        dwld_threads.append(DownloadManager.DownloadThread())

76
2017-09-17 01:12


gốc




Các câu trả lời:


Bạn có thể muốn làm điều này khi lớp "bên trong" là một lần duy nhất, mà sẽ không bao giờ được sử dụng bên ngoài Định nghĩa của lớp ngoài. Ví dụ để sử dụng một metaclass, đôi khi nó thuận tiện để làm

class Foo(object):
    class __metaclass__(type):
        .... 

thay vì xác định một metaclass riêng biệt, nếu bạn chỉ sử dụng nó một lần.

Lần duy nhất tôi đã sử dụng các lớp lồng nhau như thế, tôi đã sử dụng lớp ngoài chỉ như một vùng tên để nhóm một nhóm các lớp liên quan chặt chẽ lại với nhau:

class Group(object):
    class cls1(object):
       ...

    class cls2(object):
       ...

Sau đó, từ một mô-đun khác, bạn có thể nhập Nhóm và tham khảo các nhóm này như Group.cls1, Group.cls2 vv Tuy nhiên, người ta có thể cho rằng bạn có thể thực hiện chính xác như vậy (có thể theo cách ít gây nhầm lẫn) bằng cách sử dụng mô-đun.


99
2017-09-17 01:14



Tôi -would-tranh luận rằng trong trường hợp thứ hai, bạn sẽ sử dụng một mô-đun hoặc gói, được thiết kế để trở thành không gian tên. - Matthew Trevor
Đây là một câu trả lời tuyệt vời. Đơn giản, cho điểm, và đề cập đến phương pháp thay thế của việc sử dụng các mô-đun. +1 - CornSmith
Chỉ cần cho hồ sơ, đối với những người ngoan cố từ chối hoặc không thể tổ chức mã của họ thành một gói phân cấp và các mô-đun thích hợp, sử dụng các lớp như một không gian tên đôi khi có thể tốt hơn không sử dụng bất kỳ thứ gì. - A-B-B


Tôi không biết Python, nhưng câu hỏi của bạn có vẻ rất chung chung. Bỏ qua tôi nếu nó cụ thể cho Python.

Lớp lồng là tất cả về phạm vi. Nếu bạn nghĩ rằng một lớp sẽ chỉ có ý nghĩa trong bối cảnh của một lớp khác, thì trước đây có lẽ là một ứng cử viên tốt để trở thành một lớp lồng nhau.

Đây là một mô hình phổ biến tạo các lớp trợ giúp như là các lớp riêng tư, lồng nhau.


18
2017-09-17 01:52



Chỉ cần lưu ý cho hồ sơ, khái niệm về private các lớp không áp dụng nhiều trong Python, nhưng phạm vi sử dụng ngụ ý vẫn chắc chắn được áp dụng. - A-B-B


Có thực sự không có lợi ích để làm điều này, ngoại trừ nếu bạn đang đối phó với metaclasses.

lớp: bộ thực sự không phải là những gì bạn nghĩ. Đó là một phạm vi kỳ lạ, và nó làm những điều kỳ lạ. Nó thực sự thậm chí không làm cho một lớp học! Nó chỉ là một cách để thu thập một số biến - tên của lớp, căn cứ, một từ điển nhỏ của các thuộc tính, và một metaclass.

Tên, từ điển và các căn cứ đều được truyền cho hàm là metaclass, và sau đó nó được gán cho biến 'name' trong phạm vi mà lớp: suite là.

Những gì bạn có thể đạt được bằng cách làm lộn xộn với metaclasses, và thực sự bằng cách lồng các lớp trong các lớp tiêu chuẩn chứng khoán của bạn, khó đọc mã hơn, khó hiểu mã hơn, và các lỗi kỳ lạ khó hiểu mà không quen thuộc với lý do tại sao 'lớp' phạm vi là hoàn toàn khác với bất kỳ phạm vi python nào khác.


5
2017-09-17 01:34



Không đồng ý: Các lớp ngoại lệ lồng nhau rất hữu ích, vì người dùng trong lớp của bạn có thể kiểm tra ngoại lệ tùy chỉnh của bạn mà không phải thực hiện bất kỳ thao tác nhập nào lộn xộn. Ví dụ. except myInstanceObj.CustomError, e: - RobM
Ác ma, antipattern, mã vạch. -1 - Jerub
@ Jerub, tại sao điều đó xấu? - Robert Siemer


Bạn có thể đang sử dụng một lớp làm trình tạo lớp. Giống như (trong một số tắt mã cuff :)

class gen(object):
    class base_1(object): pass
    ...
    class base_n(object): pass

    def __init__(self, ...):
        ...
    def mk_cls(self, ..., type):
        '''makes a class based on the type passed in, the current state of
           the class, and the other inputs to the method'''

Tôi cảm thấy khi bạn cần chức năng này, nó sẽ rất rõ ràng với bạn. Nếu bạn không cần phải làm một cái gì đó tương tự hơn nó có lẽ không phải là một trường hợp sử dụng tốt.


4
2017-09-17 01:11





Không, bố cục không có nghĩa là làm tổ. Nó sẽ có ý nghĩa để có một lớp lồng nhau nếu bạn muốn ẩn nó nhiều hơn trong không gian tên của lớp bên ngoài.

Dù sao, tôi không thấy bất kỳ sử dụng thực tế để làm tổ trong trường hợp của bạn. Nó sẽ làm cho mã khó đọc hơn (hiểu) và nó cũng sẽ làm tăng sự thụt đầu dòng mà có thể làm cho các đường ngắn hơn và dễ bị tách hơn.


1





Có một cách sử dụng khác cho lớp lồng nhau, khi người ta muốn xây dựng các lớp kế thừa có chức năng nâng cao được đóng gói trong một lớp lồng nhau cụ thể.

Xem ví dụ này:

class foo:

  class bar:
    ...  # functionalities of a specific sub-feature of foo

  def __init__(self):
    self.a = self.bar()
    ...

  ...  # other features of foo


class foo2(foo):

  class bar(foo.bar):
    ... # enhanced functionalities for this specific feature

  def __init__(self):
    foo.__init__(self)

Lưu ý rằng trong hàm khởi tạo của foo, dòng self.a = self.bar() sẽ xây dựng một foo.bar khi đối tượng được xây dựng thực sự là foo đối tượng và một foo2.bar đối tượng khi đối tượng đang được xây dựng thực sự là foo2 vật.

Nếu lớp học bar được định nghĩa bên ngoài lớp foo thay vào đó, cũng như phiên bản kế thừa của nó (được gọi là bar2 ví dụ), sau đó xác định lớp mới foo2 sẽ đau đớn hơn nhiều, bởi vì foo2 sẽ cần phải có dòng đầu tiên được thay thế bằng self.a = bar2(), ngụ ý viết lại toàn bộ hàm tạo.


0