poo - Clase de instancia de Python dentro de la definición de clase
poo python 3 (4)
Estoy intentando agregar una variable a una clase que contiene instancias a la clase. La siguiente es una versión abreviada de mi código.
class Classy :
def __init__(self) :
self.hi = "HI!"
# "CLASSIES" variable holds instances of class "Classy"
CLASSIES = []
for i in xrange(0,4) :
CLASSIES.append(Classy())
Al ejecutar el código, aparece el siguiente error.
Traceback (most recent call last):
File "classy.py", line 6, in Classy
CLASSIES.append(Classy())
NameError: name ''Classy'' is not defined
¿Hay alguna otra forma de agregar instancias de una clase a una clase / variable estática dentro de esa clase?
La clase en sí misma no se define hasta después de que el bloque de clases termina de ejecutarse, por lo que no puede hacer uso de la clase dentro de su propia definición.
Puede usar un decorador de clases o una metaclase para agregar la variable de clase que desee después de crear la clase. Aquí hay un ejemplo con un decorador.
def addClassy(cls):
cls.CLASSIES = [cls() for a in xrange(4)]
return cls
@addClassy
class Classy(object):
pass
>>> Classy.CLASSIES
0: [<__main__.Classy object at 0x000000000289A240>,
<__main__.Classy object at 0x000000000289A518>,
<__main__.Classy object at 0x000000000289A198>,
<__main__.Classy object at 0x000000000289A208>]
La forma más sencilla de hacerlo es hacerlo después de crear la clase, cuando la clase se ha definido y, por lo tanto, se puede usar:
class Classy :
CLASSIES = []
def __init__(self) :
self.hi = "HI!"
Classy.CLASSIES = [Classy() for _ in xrange(0,4)]
(Aquí se usa una lista de comprensión para conveniencia, ya que es la forma más legible y eficiente de crear una lista).
También tenga en cuenta que si esto pretende ser una constante, probablemente debería hacer una tupla en lugar de una lista, y si no está destinado a ser, probablemente no debería utilizar un nombre ALL_CAPS
que, por convención, implica una constante.
Me parece que quieres obtener eso:
class Classy :
CLASSIES = []
def __init__(self) :
self.hi = "HI!"
Classy.CLASSIES.append(self)
for i in xrange(4):
Classy()
for x in Classy.CLASSIES:
print x
resultado
<__main__.Classy instance at 0x011DF3F0>
<__main__.Classy instance at 0x011DF440>
<__main__.Classy instance at 0x011DF418>
<__main__.Classy instance at 0x011DF2B0>
EDITAR
Tenga en cuenta que con el código de Lattyware:
class Classy :
CLASSIES = []
idC = id(CLASSIES)
def __init__(self) :
self.hi = "HI!"
#Classy.CLASSIES.append(self)
Classy.CLASSIES = [Classy() for _ in xrange(0,4)]
print Classy.idC
print id(Classy.CLASSIES)
print ''Classy.idC==id(Classy.CLASSIES) :'',Classy.idC==id(Classy.CLASSIES)
resultado
18713576
10755928
Classy.idC==id(Classy.CLASSIES) : False
Mientras que con el bucle for de delnan''code, no aparece.
Sin embargo, es fácil de corregir:
escritura
Classy.CLASSIES[:] = [Classy() for _ in xrange(0,4)]
o
Classy.CLASSIES.extend(Classy() for _ in xrange(0,4))
en lugar de
Classy.CLASSIES = [Classy() for _ in xrange(0,4)]
depende de lo que se desee
EDIT 2
Los métodos pueden hacer referencia a nombres globales de la misma manera que las funciones ordinarias. El alcance global asociado con un método es el módulo que contiene su definición. (Una clase nunca se usa como un alcance global).
http://docs.python.org/2/tutorial/classes.html#class-definition-syntax
Una clase tiene un espacio de nombres implementado por un objeto de diccionario. Las referencias de atributos de clase se traducen a búsquedas en este diccionario, por ejemplo,
Cx
se traduce aC.__dict__["x"]
http://docs.python.org/2/reference/datamodel.html#new-style-and-classic-classes
class Classy :
CLASSIES = []
print ''"CLASSIES" in globals()'',"CLASSIES" in globals()
print ''"CLASSIES" in Classy.__dict__ =='',"CLASSIES" in Classy.__dict__
resultado
"CLASSIES" in globals() False
"CLASSIES" in Classy.__dict__ == True
Delnan, ¿cómo vas a seguir pretendiendo que CLASSIES es global?
¿Entendí mal algo en su debate con Lattyware?
El cuerpo de la clase se ejecuta antes de que se cree la clase. Por lo tanto, está intentando crear una instancia de la clase antes de que exista. Todavía puede adjuntar instancias a la clase, pero debe crearlas después de que el cuerpo de la clase haya terminado, por ejemplo:
class Classy(object):
def __init__(self):
self.hi = "HI!"
CLASSIES = []
for i in xrange(4):
Classy.CLASSIES.append(Classy())
Sin embargo, le sugiero que primero piense detenidamente si realmente necesita esta lista global efectiva y si necesita que sea parte del objeto de la clase. Personalmente, casi nunca hago algo como esto.