programacion poo otra orientada objetos metodo llamar lista instancia importar clases clase python scope nested-class

poo - La clase anidada de Python necesita acceder a la variable en la clase adjunta



poo python 3 (6)

He visto algunas "soluciones" a esto, pero la solución siempre parece ser "No use clases anidadas, defina las clases fuera y luego úselos normalmente". No me gusta esa respuesta porque ignora la razón principal por la que elegí las clases anidadas, que es tener un conjunto de constantes (asociadas a la clase base) accesible para todas las instancias de subclase que se crean.

Aquí hay un código de ejemplo:

class ParentClass: constant_pool = [] children = [] def __init__(self, stream): self.constant_pool = ConstantPool(stream) child_count = stream.read_ui16() for i in range(0, child_count): children.append(ChildClass(stream)) class ChildClass: name = None def __init__(self, stream): idx = stream.read_ui16() self.name = constant_pool[idx]

A todas las clases se les pasa un solo parámetro, que es una clase de bitstream personalizada. Mi intención es tener una solución que no requiera que lea el valor de idx para ChildClass mientras esté todavía en ParentClass. Toda la lectura de la secuencia de la clase infantil debe hacerse en la clase infantil.

Este ejemplo está más simplificado. El conjunto constante no es la única variable que necesito disponible para todas las subclases. La variable idx no es lo único que se lee del lector de flujo.

¿Es esto posible en Python? ¿No hay forma de acceder a la información de los padres?


A pesar de mi comentario "poco condescendiente" (¡juego limpio para llamarlo así!), En realidad hay formas de lograr lo que quieres: una avenida de herencia diferente. Una pareja:

  1. Escriba un decorador que introspecte una clase justo después de que haya sido declarada, encuentre las clases internas y copie los atributos de la clase externa en ellas.

  2. Haz lo mismo con una metaclase.

Aquí está el enfoque del decorador, ya que es el más directo:

def matryoshka(cls): # get types of classes class classtypes: pass classtypes = (type, type(classtypes)) # get names of all public names in outer class directory = [n for n in dir(cls) if not n.startswith("_")] # get names of all non-callable attributes of outer class attributes = [n for n in directory if not callable(getattr(cls, n))] # get names of all inner classes innerclasses = [n for n in directory if isinstance(getattr(cls, n), classtypes)] # copy attributes from outer to inner classes (don''t overwrite) for c in innerclasses: c = getattr(cls, c) for a in attributes: if not hasattr(c, a): setattr(c, a, getattr(cls, a)) return cls

Aquí hay un ejemplo simple de su uso:

@matryoshka class outer(object): answer = 42 class inner(object): def __call__(self): print self.answer outer.inner()() # 42

Sin embargo, no puedo evitar pensar que algunas de las ideas sugeridas en otras respuestas te servirían mejor.


Bueno, los siguientes trabajos (más simplificado de su ejemplo). Tenga en cuenta que no tiene que "declarar" variables miembro en el nivel de clase como C ++ / C # / Java, etc., simplemente __init__ en self dentro de __init__ :

class ParentClass: def __init__(self): self.constant_pool = ["test"] self.ChildClass.constant_pool = self.constant_pool self.children = [self.ChildClass()] class ChildClass: def __init__(self): self.name = self.constant_pool[0] print "child name is", self.name p = ParentClass() # Prints "child name is test"

Tenga en cuenta que aún podría hacer el mismo tipo de cosas sin anidar las clases secundarias.


No necesitas dos clases aquí. Aquí está su código de ejemplo escrito de una manera más concisa.

class ChildClass: def __init__(self, stream): idx = stream.read_ui16() self.name = self.constant_pool[idx] def makeChildren(stream): ChildClass.constant_pool = ConstantPool(stream) return [ChildClass(stream) for i in range(stream.read_ui16())]

Bienvenido a Python. Las clases son mutables en tiempo de ejecución. Disfrutar.


Otro diseño alternativo a considerar:

Cuando se encuentre tratando de usar clases como espacios de nombres, podría tener más sentido colocar las clases internas en un módulo propio y hacer cuáles eran los atributos de las variables globales de la clase externa. En otras palabras, si nunca intenta crear una instancia de su ParentClass , entonces solo sirve como un módulo glorificado.

Las variables globales tienen mala reputación en la mayoría de los lenguajes de programación, pero no son realmente globales en Python, y están muy bien encapsuladas para el módulo.


Puede acceder a la clase principal a través de su nombre:

class ChildClass: name = None def __init__(self, stream): idx = stream.read_ui16() self.name = ParentClass.constant_pool[idx]

Por otra parte, no estoy seguro de entender lo que estás tratando de lograr.


Su pregunta usa la palabra subclase, así que estoy desviando de eso para interpretar su pregunta. Al igual que los demás que respondieron, no estoy seguro de entender lo que estás buscando.

class ParentClass(object): constant_pool = [c1, c2, c3] def __init__(self): # anything not included in your question class ChildClass(ParentClass): def __init__(self, stream): ParentClass.__init__(self) self.name = ParentClass.constant_pool[stream.read_ui16()] stream = get_new_stream() children = [] for count in range(stream.read_ui16()): children.append(ChildClass(stream))

Este código usa herencia para derivar ChildClass de ParentClass (y todos los métodos, etc.). El constant_pool es un atributo de ParentClass, aunque está bien tratarlo como un atributo de cualquier instancia de ParentClass o ChildClass (decir self.constant_pool dentro de ChildClass.__init__ sería equivalente al anterior pero, en mi opinión, engañoso).

Anidar las definiciones de clase no es necesario. Anidar la definición de ChildClass dentro de ParentClass solo significa que ChildClass es un atributo de ParentClass, nada más. No hace que las instancias de ChildClass hereden algo de ParentClass.