web-dev-qa-db-fra.com

Y a-t-il un avantage à définir une classe à l'intérieur d'une autre classe en Python?

Je parle ici de classes imbriquées. Essentiellement, j'ai deux classes que je modélise. Une classe DownloadManager et une classe DownloadThread. Le concept évident OOP ici est la composition. Cependant, la composition ne signifie pas nécessairement l'imbrication, non?

J'ai du code qui ressemble à ceci:

class DownloadThread:
    def foo(self):
        pass

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

Mais maintenant, je me demande s'il y a une situation où la nidification serait meilleure. Quelque chose comme:

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

Vous voudrez peut-être le faire lorsque la classe "interne" est unique, qui ne sera jamais utilisée en dehors de la définition de la classe externe. Par exemple, pour utiliser une métaclasse, il est parfois pratique de faire

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

au lieu de définir une métaclasse séparément, si vous ne l'utilisez qu'une seule fois.

La seule fois où j'ai utilisé des classes imbriquées comme ça, j'ai utilisé la classe externe uniquement comme un espace de noms pour regrouper un tas de classes étroitement liées:

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

    class cls2(object):
       ...

Ensuite, à partir d'un autre module, vous pouvez importer Group et les appeler Group.cls1, Group.cls2, etc.

108
dF.

Je ne connais pas Python, mais votre question semble très générale. Ignorez-moi si c'est spécifique à Python.

L'imbrication de classe est une question de portée. Si vous pensez qu'une classe n'aura de sens que dans le contexte d'une autre, alors la première est probablement un bon candidat pour devenir une classe imbriquée.

C'est un modèle courant qui fait des classes auxiliaires des classes privées imbriquées.

18
André Chalella

Il n'y a vraiment aucun avantage à faire cela, sauf si vous avez affaire à des métaclasses.

la classe: la suite n'est vraiment pas ce que vous pensez. C'est une portée étrange et cela fait des choses étranges. Ça ne fait même pas un cours! C'est juste un moyen de collecter certaines variables - le nom de la classe, les bases, un petit dictionnaire d'attributs et une métaclasse.

Le nom, le dictionnaire et les bases sont tous passés à la fonction qui est la métaclasse, puis il est affecté à la variable "nom" dans la portée où se trouvait la classe: suite.

Ce que vous pouvez gagner en jouant avec les métaclasses, et en effet en imbriquant les classes dans vos classes standard stock, est plus difficile à lire le code, plus difficile à comprendre le code et les erreurs impaires qui sont terriblement difficiles à comprendre sans être intimement familier avec pourquoi la `` classe '' la portée est entièrement différente de toute autre portée python.

6
Jerub

Vous pourriez utiliser une classe comme générateur de classe. Comme (dans certains hors du code manchette :)

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

J'ai l'impression que lorsque vous aurez besoin de cette fonctionnalité, elle sera très claire pour vous. Si vous n'avez pas besoin de faire quelque chose de similaire, ce n'est probablement pas un bon cas d'utilisation.

5
tim.tadh

Il existe une autre utilisation de la classe imbriquée, lorsque l'on veut construire des classes héritées dont les fonctionnalités améliorées sont encapsulées dans une classe imbriquée spécifique.

Voir cet exemple:

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)

Notez que dans le constructeur de foo, la ligne self.a = self.bar() construira un foo.bar Lorsque l'objet en cours de construction est en fait un objet foo et un foo2.bar Objet lorsque l'objet en cours de construction est en fait un objet foo2.

Si la classe bar a été définie à l'extérieur de la classe foo à la place, ainsi que sa version héritée (qui serait appelée bar2 Par exemple), alors définir la nouvelle classe foo2 Serait beaucoup plus pénible, car le constructeur de foo2 Devrait avoir sa première ligne remplacée par self.a = bar2(), ce qui implique de réécrire tout le constructeur.

4
Thomas

Non, la composition ne signifie pas la nidification. Il serait judicieux d'avoir une classe imbriquée si vous souhaitez la cacher davantage dans l'espace de noms de la classe externe.

Quoi qu'il en soit, je ne vois aucune utilité pratique pour l'imbrication dans votre cas. Cela rendrait le code plus difficile à lire (comprendre) et augmenterait également l'indentation, ce qui rendrait les lignes plus courtes et plus sujettes à la division.

1
Cristian Ciupitu