Accede a la clase externa desde la clase interna en python

Tengo una situación así …

class Outer(object): def some_method(self): # do something class Inner(object): def __init__(self): self.Outer.some_method() # <-- this is the line in question 

¿Cómo puedo acceder al método de la clase Outer desde la clase Inner ?

Editar – Gracias por las respuestas. Estoy concluyendo que necesito volver a evaluar cómo había diseñado esto para implementarlo y encontrar un método más sólido.

Los métodos de una clase anidada no pueden acceder directamente a los atributos de instancia de la clase externa.

Tenga en cuenta que no es necesariamente el caso de que exista una instancia de la clase externa, incluso cuando haya creado una instancia de la clase interna.

De hecho, a menudo se recomienda no usar clases anidadas, ya que la anidación no implica ninguna relación particular entre las clases internas y externas.

Estás intentando acceder a la instancia de clase de Outer, desde la instancia de clase interna. Así que solo use el método de fábrica para crear una instancia interna y pasarle una instancia externa.

 class Outer(object): def createInner(self): return Outer.Inner(self) class Inner(object): def __init__(self, outer_instance): self.outer_instance = outer_instance self.outer_instance.somemethod() def inner_method(self): self.outer_instance.anothermethod() 

tal vez estoy enojado, pero esto parece muy fácil, la cosa es convertir a tu clase interna dentro de un método de la clase externa …

 def do_sthg( self ): ... def messAround( self ): outerClassSelf = self class mooble(): def do_sthg_different( self ): ... outerClassSelf.do_sthg() 

Además … “self” solo se usa por convención, así que puedes hacer esto:

 def do_sthg( self ): ... def messAround( outerClassSelf ): class mooble(): def do_sthg_different( self ): ... outerClassSelf.do_sthg() 

Podría objetarse que no puede crear esta clase interna desde fuera de la clase externa … pero esto no es cierto:

 class Bumblebee(): def do_sthg( self ): print "sthg" def giveMeAnInnerClass( outerClassSelf ): class mooble(): def do_sthg_different( self ): print "something diff\n" outerClassSelf.do_sthg() return mooble 

Luego, en algún lugar a millas de distancia:

 blob = Bumblebee().giveMeAnInnerClass()() blob.do_sthg_different() 

incluso empuje el bote un poco y extienda esta clase interna (NB para que funcione super () debe cambiar la firma de la clase de mooble a “class mooble (objeto)”

 class InnerBumblebeeWithAddedBounce( Bumblebee().giveMeAnInnerClass() ): def bounce( self ): print "bounce" def do_sthg_different( self ): super( InnerBumblebeeWithAddedBounce, self ).do_sthg_different() print "and more different" ibwab = InnerBumblebeeWithAddedBounce() ibwab.bounce() ibwab.do_sthg_different() 

luego

mrh1997 planteó un punto interesante sobre la herencia no común de las clases internas entregadas utilizando esta técnica. Pero parece que la solución es bastante sencilla:

 class Fatty(): def do_sthg( self ): pass class InnerFatty( object ): pass def giveMeAnInnerFattyClass(self): class ExtendedInnerFatty( Fatty.InnerFatty ): pass return ExtendedInnerFatty fatty1 = Fatty() fatty2 = Fatty() innerFattyClass1 = fatty1.giveMeAnInnerFattyClass() innerFattyClass2 = fatty2.giveMeAnInnerFattyClass() print ( issubclass( innerFattyClass1, Fatty.InnerFatty )) print ( issubclass( innerFattyClass2, Fatty.InnerFatty )) 

¿Quieres usar la herencia en lugar de clases de anidación como esta? Lo que estás haciendo no tiene mucho sentido en Python.

Puede acceder al some_method de Outer simplemente Outer.some_method referencia a Outer.some_method dentro de los métodos de la clase interna, pero no va a funcionar como espera. Por ejemplo, si intentas esto:

 class Outer(object): def some_method(self): # do something class Inner(object): def __init__(self): Outer.some_method() 

… obtendrá un TypeError al inicializar un objeto Inner , porque Outer.some_method espera recibir una instancia Outer como su primer argumento. (En el ejemplo anterior, básicamente intentas llamar a some_method como un método de clase de Outer ).

He creado algún código Python para usar una clase externa de su clase interna , basado en una buena idea de otra respuesta para esta pregunta. Creo que es corto, simple y fácil de entender.

 class higher_level__unknown_irrelevant_name__class: def __init__(self, ...args...): ...other code... # Important lines to access sub-classes. subclasses = self._subclass_container() self.some_subclass = subclasses["some_subclass"] del subclasses # Free up variable for other use. def sub_function(self, ...args...): ...other code... def _subclass_container(self): _parent_class = self # Create access to parent class. class some_subclass: def __init__(self): self._parent_class = _parent_class # Easy access from self. # Optional line, clears variable space, but SHOULD NOT BE USED # IF THERE ARE MULTIPLE SUBCLASSES as would stop their parent access. # del _parent_class class subclass_2: def __init__(self): self._parent_class = _parent_class # Return reference(s) to the subclass(es). return {"some_subclass": some_subclass, "subclass_2": subclass_2} 

El código principal, “producción lista” (sin comentarios, etc.). Recuerde reemplazar todos los valores entre paréntesis angulares (por ejemplo, ) con el valor deseado.

 class : def __init__(self): subclasses = self._subclass_container() self. = subclasses[] del subclasses def _subclass_container(self): _parent_class = self class : def __init__(self): self._parent_class = _parent_class return {: } 

Explicación de cómo funciona este método (los pasos básicos):

  1. Cree una función llamada _subclass_container para que actúe como un contenedor para acceder a la variable self , una referencia a la clase de nivel superior (desde el código que se ejecuta dentro de la función).

    1. Cree una variable llamada _parent_class que es una referencia a la variable self de esta función, a la que pueden acceder las _subclass_container de _subclass_container (evita los conflictos de nombre con otras variables self en las subclases).

    2. Devuelva la subclase / subclases como un diccionario / lista para que el código que llame a la función _subclass_container pueda acceder a las subclases dentro.

  2. En la función __init__ dentro de la clase de nivel superior (o donde sea necesario), reciba las subclases devueltas de la función _subclass_container en las subclasses variables.

  3. Asigne subclases almacenadas en la variable de subclasses a los atributos de la clase de nivel superior.

Algunos consejos para hacer los escenarios más fáciles:

Hacer que el código para asignar las subclases a la clase de nivel superior sea más fácil de copiar y se use en las clases derivadas de la clase de nivel superior que tienen su función __init__ cambiada:

Insertar antes de la línea 12 en el código principal:

  def _subclass_init(self): 

Luego inserte en esta función las líneas 5-6 (del código principal) y reemplace las líneas 4-7 con el siguiente código:

  self._subclass_init(self) 

Hacer posible la asignación de subclases a la clase de nivel superior cuando hay muchas / desconocidas cantidades de subclases.

Reemplace la línea 6 con el siguiente código:

  for subclass_name in list(subclasses.keys()): setattr(self, subclass_name, subclasses[subclass_name]) 

Ejemplo de escenario en el que esta solución sería útil y donde el nombre de la clase de nivel superior debería ser imposible de obtener:

Se crea una clase, llamada “a” ( class a: :). Tiene subclases que necesitan acceder a él (el padre). Una subclase se llama “x1”. En esta subclase, se ejecuta el código a.run_func() .

Luego se crea otra clase, llamada “b”, derivada de la clase “a” ( class b(a): . Después de eso, algunos códigos ejecutan b.x1() (llamando a la subfunción “x1” de b, una subclase derivada). Esta función ejecuta a.run_func() , llamando a la función “run_func” de la clase “a”, no a la función “run_func” de su padre, “b” (como debería), porque la función que se definió en la clase “a “se establece para referirse a la función de la clase” a “, ya que era su padre.

Esto causaría problemas (por ejemplo, si la función a.run_func ha sido eliminada) y la única solución sin volver a escribir el código en la clase a.x1 sería redefinir la subclase x1 con el código actualizado para todas las clases derivadas de la clase “a” que Obviamente sería difícil y no valdría la pena.

Otra posibilidad:

 class _Outer (object): # Define your static methods here, eg @staticmethod def subclassRef (): return Outer class Outer (_Outer): class Inner (object): def outer (self): return _Outer def doSomething (self): outer = self.outer () # Call your static mehthods. cls = outer.subclassRef () return cls () 

Puede acceder fácilmente a la clase externa usando metaclase: después de la creación de la clase externa, verifique el atributo dict para cualquier clase (o aplique cualquier lógica que necesite; el mío es solo un ejemplo trivial) y establezca los valores correspondientes:

 import six import inspect # helper method from `peewee` project to add metaclass _METACLASS_ = '_metaclass_helper_' def with_metaclass(meta, base=object): return meta(_METACLASS_, (base,), {}) class OuterMeta(type): def __new__(mcs, name, parents, dct): cls = super(OuterMeta, mcs).__new__(mcs, name, parents, dct) for klass in dct.values(): if inspect.isclass(klass): print("Setting outer of '%s' to '%s'" % (klass, cls)) klass.outer = cls return cls # @six.add_metaclass(OuterMeta) -- this is alternative to `with_metaclass` class Outer(with_metaclass(OuterMeta)): def foo(self): return "I'm outer class!" class Inner(object): outer = None # <-- by default it's None def bar(self): return "I'm inner class" print(Outer.Inner.outer) >>>  assert isinstance(Outer.Inner.outer(), Outer) print(Outer().foo()) >>> I'm outer class! print(Outer.Inner.outer().foo()) >>> I'm outer class! print(Outer.Inner().outer().foo()) >>> I'm outer class! print(Outer.Inner().bar()) >>> I'm inner class! 

Usando este enfoque, puede enlazar y referir fácilmente dos clases entre sí.

Ampliando el pensamiento convincente de @ tsnorri, que el método externo puede ser un método estático :

 class Outer(object): @staticmethod def some_static_method(self): # do something class Inner(object): def __init__(self): self.some_static_method() # <-- this will work later Inner.some_static_method = some_static_method 

Ahora la línea en cuestión debería funcionar para cuando se llame.

La última línea del código anterior le da a la clase Interna un método estático que es un clon del método estático externo.


Esto aprovecha dos características de Python, que las funciones son objetos y el scope es textual .

Generalmente, el ámbito local hace referencia a los nombres locales de la función actual (textualmente).

... o clase actual en nuestro caso. Por lo tanto, los objetos "locales" a la definición de la clase Externa ( Inner y some_static_method ) pueden referirse directamente dentro de esa definición.

encontré esto

Ajustado para adaptarse a su pregunta, es la respuesta:

 class Outer(object): def some_method(self): # do something class _Inner(object): def __init__(self, outer): outer.some_method() def Inner(self): return _Inner(self) 

Estoy seguro de que de alguna manera puedes escribir un decorador para esto o algo 🙂
/ edit: un poco