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:
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.
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.