Pregunta ¿Hay algún beneficio en definir una clase dentro de otra clase en Python?


De lo que estoy hablando aquí son clases anidadas. Esencialmente, tengo dos clases que estoy modelando. Una clase DownloadManager y una clase DownloadThread. El concepto obvio de OOP aquí es la composición. Sin embargo, la composición no necesariamente significa anidar, ¿verdad?

Tengo un código que se ve así:

class DownloadThread:
    def foo(self):
        pass

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

Pero ahora me pregunto si hay una situación en la que anidar sería mejor. Algo como:

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


origen


Respuestas:


Es posible que desee hacer esto cuando la clase "interna" sea única, que nunca se utilizará fuera de la clase. definición de la clase externa. Por ejemplo, para usar una metaclase, a veces es útil hacerlo

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

en lugar de definir una metaclase por separado, si solo la está utilizando una vez.

La única otra vez que utilicé clases anidadas como esa, utilicé la clase externa solo como un espacio de nombres para agrupar un grupo de clases estrechamente relacionadas entre sí:

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

    class cls2(object):
       ...

Luego, desde otro módulo, puede importar Group y referirse a éstos como Group.cls1, Group.cls2, etc. Sin embargo, se podría argumentar que puede lograr exactamente lo mismo (quizás de una manera menos confusa) mediante el uso de un módulo.


99
2017-09-17 01:14



No conozco a Python, pero su pregunta parece muy general. Ignorarme si es específico de Python.

La anidación de clases tiene que ver con el alcance. Si crees que una clase solo tendrá sentido en el contexto de otra, entonces la primera es probablemente una buena candidata para convertirse en una clase anidada.

Es un patrón común que hace que las clases auxiliares sean clases privadas y anidadas.


18
2017-09-17 01:52



Realmente no hay ningún beneficio al hacer esto, excepto si se trata de metaclases.

la clase: suite realmente no es lo que crees que es. Es un alcance extraño, y hace cosas extrañas. ¡Realmente ni siquiera hace una clase! Es solo una forma de recopilar algunas variables: el nombre de la clase, las bases, un pequeño diccionario de atributos y una metaclase.

El nombre, el diccionario y las bases se pasan a la función que es la metaclase, y luego se asigna a la variable 'nombre' en el alcance donde estaba la clase: suite.

Lo que puede ganar jugando con metaclases y, de hecho, anidando clases dentro de sus clases estándar, es más difícil de leer código, código más difícil de entender y errores extraños que son terriblemente difíciles de entender sin estar íntimamente familiarizado con por qué la 'clase' el alcance es completamente diferente a cualquier otro ámbito de Python.


5
2017-09-17 01:34



Podrías estar usando una clase como generador de clases. Me gusta (en algunos fuera del código de manguito :)

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

Siento que cuando necesites esta funcionalidad, será muy claro para ti. Si no necesita hacer algo similar, probablemente no sea un buen caso de uso.


4
2017-09-17 01:11



No, la composición no significa anidar. Tendría sentido tener una clase anidada si desea ocultarla más en el espacio de nombres de la clase externa.

De todos modos, no veo ningún uso práctico para anidar en su caso. Haría que el código fuera más difícil de leer (entender) y también aumentaría la sangría que haría las líneas más cortas y más propensas a la división.


1



Hay otro uso para la clase anidada, cuando uno quiere construir clases heredadas cuyas funcionalidades mejoradas están encapsuladas en una clase anidada específica.

Mira este ejemplo:

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)

Tenga en cuenta que en el constructor de foo, la línea self.a = self.bar() construirá un foo.bar cuando el objeto que se está construyendo es en realidad un foo objeto y una foo2.bar objeto cuando el objeto que se está construyendo es en realidad una foo2 objeto.

Si la clase bar fue definido fuera de clase foo en cambio, así como su versión heredada (que se llamaría bar2 por ejemplo), luego definir la nueva clase foo2 sería mucho más doloroso, porque el constuctor de foo2 necesitaría tener su primera línea reemplazada por self.a = bar2(), lo que implica volver a escribir todo el constructor.


0