it-swarm-vi.tech

Có một lợi ích nào khi định nghĩa một lớp bên trong một lớp khác trong Python không?

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 người mẫu. Một lớp DownloadManager và một lớp DownloadThread. Khái niệm rõ ràng OOP ở đây là thành phần. Tuy nhiên, thành phần không nhất thiết có nghĩa là lồng nhau, 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 đang tự hỏi nếu có một tình huống 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())
90
fuentesjr

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

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

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

Lần khác tôi đã sử dụng các lớp lồng nhau như vậy, tôi chỉ sử dụng lớp bên ngoài làm không gian tên để nhóm một nhóm các lớp có liên quan chặt chẽ 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, v.v. Tuy nhiên, người ta có thể lập luận 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 hơn) bằng cách sử dụng mô-đun.

108
dF.

Tôi không biết Python, nhưng câu hỏi của bạn có vẻ rất chung chung. Mặc kệ tôi nếu nó dành riêng 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ì lớp trước có lẽ là một ứng cử viên tốt để trở thành một lớp lồng nhau.

Đó là một mô hình phổ biến làm cho các lớp của trình trợ giúp là các lớp riêng, lồng nhau.

18
André Chalella

Thực sự không có lợi ích gì khi làm điều này, ngoại trừ nếu bạn đang làm việc với metaclass.

lớp: bộ thực sự không như 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 tạo ra 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ác cơ sở, một từ điển nhỏ của các thuộc tính và một siêu dữ liệu.

Tên, từ điển và các cơ sở đều được truyền cho hàm đó là siêu dữ liệu, và sau đó nó được gán cho biến 'name' trong phạm vi nơi lớp: bộ.

Những gì bạn có thể đạt được bằng cách làm rối với siêu dữ liệu 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ạ rất khó hiểu mà không hiểu rõ về lý do tại sao 'lớp' phạm vi hoàn toàn khác với bất kỳ phạm vi nào khác python.

6
Jerub

Bạn có thể sử dụng một lớp làm trình tạo lớp. Giống như (trong một số 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 như 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ự như nó có thể không phải là một trường hợp sử dụng tốt.

5
tim.tadh

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 được kế thừa có các chức năng nâng cao được gói gọn trong một lớp lồng 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 tạo của foo, dòng self.a = self.bar() sẽ xây dựng một _foo.bar_ khi đối tượng đang được xây dựng thực sự là một đối tượng foo và một _foo2.bar_ đối tượng khi đối tượng đang được xây dựng thực sự là một đối tượng _foo2_.

Thay vào đó, nếu lớp bar được xác định bên ngoài lớp foo, cũng như phiên bản được kế thừa của nó (ví dụ sẽ được gọi là _bar2_), sau đó xác định lớp mới _foo2_ sẽ đau đớn hơn nhiều, bởi vì bộ tạo của _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.

4
Thomas

Không, thành phần không có nghĩa là làm tổ. Sẽ có ý nghĩa khi 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ế nào để 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 dòng, điều này sẽ làm cho các dòng ngắn hơn và dễ bị phân tách hơn.

1
Cristian Ciupitu