Pertanyaan Apakah ada manfaat untuk mendefinisikan kelas di dalam kelas lain dengan Python?


Yang saya bicarakan di sini adalah kelas bertingkat. Intinya, saya punya dua kelas yang saya modelling. Kelas DownloadManager dan kelas DownloadThread. Konsep OOP yang jelas di sini adalah komposisi. Namun, komposisi tidak selalu berarti bersarang, bukan?

Saya memiliki kode yang terlihat seperti ini:

class DownloadThread:
    def foo(self):
        pass

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

Tapi sekarang aku bertanya-tanya apakah ada situasi di mana bersarang akan menjadi lebih baik. Sesuatu seperti:

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


asal


Jawaban:


Anda mungkin ingin melakukan ini ketika kelas "dalam" adalah satu kali, yang tidak akan pernah digunakan di luar definisi dari kelas luar. Misalnya untuk menggunakan metaclass, terkadang berguna untuk dilakukan

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

alih-alih mendefinisikan metaclass secara terpisah, jika Anda hanya menggunakannya sekali.

Satu-satunya waktu lain saya telah menggunakan kelas bersarang seperti itu, saya menggunakan kelas luar hanya sebagai namespace untuk mengelompokkan sekelompok kelas yang terkait erat bersama-sama:

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

    class cls2(object):
       ...

Kemudian dari modul lain, Anda dapat mengimpor Group dan merujuk ini sebagai Group.cls1, Group.cls2, dll. Namun orang mungkin berpendapat bahwa Anda dapat mencapai hal yang sama (mungkin dengan cara yang kurang membingungkan) dengan menggunakan modul.


99
2017-09-17 01:14



Saya tidak tahu Python, tetapi pertanyaan Anda tampaknya sangat umum. Abaikan saya jika itu khusus untuk Python.

Kelas bersarang adalah semua tentang ruang lingkup. Jika Anda berpikir bahwa satu kelas hanya akan masuk akal dalam konteks yang lain, maka yang pertama mungkin adalah kandidat yang baik untuk menjadi kelas bertingkat.

Ini adalah pola umum yang membuat kelas pembantu sebagai pribadi, kelas bertingkat.


18
2017-09-17 01:52



Benar-benar tidak ada manfaat untuk melakukan ini, kecuali jika Anda berurusan dengan metaclasses.

kelas: suite benar-benar bukan seperti yang Anda pikirkan. Ini adalah lingkup yang aneh, dan itu melakukan hal-hal aneh. Itu benar-benar bahkan tidak membuat kelas! Ini hanyalah cara mengumpulkan beberapa variabel - nama kelas, basis, kamus kecil atribut, dan metaclass.

Nama, kamus dan basis semua dilewatkan ke fungsi yang merupakan metaclass, dan kemudian ditugaskan ke 'nama' variabel dalam ruang lingkup di mana kelas: suite itu.

Apa yang bisa Anda peroleh dengan mengotak-atik kacamata hitam, dan memang dengan menempatkan kelas dalam kelas standar saham Anda, lebih sulit untuk membaca kode, lebih sulit untuk memahami kode, dan kesalahan aneh yang sangat sulit dipahami tanpa akrab dengan mengapa 'kelas' ruang lingkup sepenuhnya berbeda dengan lingkup python lainnya.


5
2017-09-17 01:34



Anda bisa menggunakan kelas sebagai generator kelas. Seperti (di beberapa kode manset :)

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'''

Saya merasa seperti ketika Anda membutuhkan fungsi ini akan sangat jelas bagi Anda. Jika Anda tidak perlu melakukan sesuatu yang serupa dari itu mungkin bukan kasus penggunaan yang baik.


4
2017-09-17 01:11



Tidak, komposisi tidak berarti bersarang. Akan masuk akal untuk memiliki kelas bertingkat jika Anda ingin menyembunyikannya lebih dalam namespace dari kelas luar.

Bagaimanapun, saya tidak melihat ada penggunaan praktis untuk bersarang dalam kasus Anda. Ini akan membuat kode lebih sulit untuk dibaca (dimengerti) dan itu juga akan meningkatkan indentasi yang akan membuat garis lebih pendek dan lebih rentan untuk membelah.


1



Ada penggunaan lain untuk kelas bertingkat, ketika seseorang ingin membangun kelas yang diwariskan yang fungsinya ditingkatkan diringkas dalam kelas bertingkat tertentu.

Lihat contoh ini:

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)

Perhatikan bahwa dalam konstruktor foo, garis self.a = self.bar() akan membangun sebuah foo.bar ketika objek yang sedang dibangun sebenarnya adalah a foo objek, dan a foo2.bar objek ketika objek yang sedang dibangun sebenarnya adalah a foo2 obyek.

Jika kelas bar didefinisikan di luar kelas foo sebagai gantinya, serta versi turunannya (yang akan dipanggil bar2 misalnya), kemudian mendefinisikan kelas baru foo2 akan jauh lebih menyakitkan, karena konstuktor foo2 harus memiliki baris pertama diganti oleh self.a = bar2(), yang berarti menulis ulang seluruh konstruktor.


0