2010-04-24 22 views
8

He aquí un ejemplo muy simple de lo que estoy tratando de moverse:__init__ clase (no __init__ ejemplo)

class Test(object): 
    some_dict = {Test: True} 

El problema es que no puedo hacer referencia a la prueba mientras aún está siendo definido

Normalmente, me gustaría hacer esto:

class Test(object): 
    some_dict = {} 
    def __init__(self): 
     if self.__class__.some_dict == {}: 
      self.__class__.some_dict = {Test: True} 

Pero nunca creo una instancia de esta clase. No deja de ser un recipiente para contener un grupo de funciones y datos relacionados (tengo varias de estas clases, y paso alrededor de las referencias a ellos, por lo que es necesaria para la prueba de que sea la propia clase)

Así que mi La pregunta es, ¿cómo podría referirme a Test mientras se está definiendo, o hay algo similar a __init__ que se llama tan pronto como se define la clase? Si es posible, quiero que self.some_dict = {Test: True} permanezca dentro de la definición de la clase. Esta es la única manera que sé cómo hacer esto hasta ahora:

class Test(object): 
    @classmethod 
    def class_init(cls): 
     cls.some_dict = {Test: True} 
Test.class_init() 
+0

"El problema es que no puedo referirme a la prueba mientras todavía se está definiendo". ¿Asi que? ¿Qué tipo de referencia posible necesitas ** durante la definición **? La respuesta estándar es Ninguna: la definición de clase es estable, constante e invariante. ** Comportamiento ** puede cambiar. La definición no debe cambiar. ¿Qué estás tratando de hacer con este negocio de "definición variable"? –

+0

La definición no está cambiando. Solo necesito una referencia a la clase, y para fines de organización, preferiría que establezca esa referencia cuando se esté definiendo la clase. – Ponkadoodle

+0

Entiendo lo que estás tratando de hacer, pero no entiendo por qué estás tratando de hacerlo de esta manera y lo que estás buscando lograr. ¿Puedes elaborar un poco? Parece más arquitectónico que un "¿cómo convenzo a Python en ...?" problema para mí – Aea

Respuesta

12

La clase, de hecho, no existe mientras se está definiendo. La forma en que funciona la instrucción class es que el cuerpo de la instrucción se ejecuta, como un bloque de código, en un espacio de nombres separado. Al final de la ejecución, ese espacio de nombres se pasa a la metaclase (como type) y la metaclase crea la clase usando el espacio de nombres como el espacio de atributos.

De su descripción, hace no sonido necesario para que Test sea una clase. Parece que debería ser un módulo . some_dict es global, incluso si se trata de un atributo de clase, solo hay un atributo de ese tipo en su programa, por lo que no es mejor que tener un sistema global, y cualquier método de clase que tenga en la clase puede ser simplemente funciones.

Si realmente quiere que sea una clase, usted tiene tres opciones: establecer el dict después de definir la clase:

class Test: 
    some_dict = {} 
Test.some_dict[Test] = True 

Usar un decorador de clase (en Python 2.6 o posterior):

def set_some_dict(cls): 
    cls.some_dict[cls] = True 

@set_some_dict 
class Test: 
    some_dict = {} 

O utilizar una metaclase:

class SomeDictSetterType(type): 
    def __init__(self, name, bases, attrs): 
     self.some_dict[self] = True 
     super(SomeDictSetterType, self).__init__(name, bases, attrs) 

class Test(object): 
    __metaclass__ = SomeDictSetterType 
    some_dict = {} 
+0

+1 para obtener una respuesta detallada –

+0

Es * podría * ser un módulo, pero preferiría que fuera una clase. Si estuviera en un módulo separado, tendría que hacer un poco de reorganización para evitar las importaciones circulares. Además, necesitaría tener 20 pestañas abiertas al editar mi proyecto si todas esas clases estuvieran en archivos diferentes. De todos modos, gracias por contarme sobre las Metaclases. – Ponkadoodle

+0

el decorador es un enfoque genial –

4

Se podría añadir el atributo some_dict después de la definición de la clase principal.

class Test(object): 
    pass 
Test.some_dict = {Test: True} 
+0

Esta es la forma de hacerlo. – PaulMcG

+0

De acuerdo, esta es la respuesta correcta. –

0

también puede utilizar una metaclase (una función aquí, pero hay otras maneras) :

def Meta(name, bases, ns): 
    klass = type(name, bases, ns) 
    setattr(klass, 'some_dict', { klass: True }) 
    return klass 

class Test(object): 
    __metaclass__ = Meta 

print Test.some_dict 
0

El primer ejemplo de Thomas es muy bueno, pero aquí hay una manera más pitoniana de hacer lo mismo.

class Test: 
    x = {} 
    @classmethod 
    def init(cls): 
     # do whatever setup you need here 
     cls.x[cls] = True 
Test.init() 
1

He tratado de utilizar las clases de esta manera en el pasado, y se pone feo con bastante rapidez (por ejemplo, todos los métodos tendrán que ser los métodos de clase o métodos estáticos, y probablemente se darán cuenta con el tiempo que quiere definir ciertos métodos especiales, para los cuales deberá comenzar a usar metaclases).Podría hacer las cosas mucho más fáciles si solo usara instancias de clase en su lugar, en realidad no hay inconvenientes.

A (raro de aspecto) como alternativa a lo que otros han sugerido: usted podría utilizar __new__:

class Test(object): 
    def __new__(cls): 
     cls.some_dict = {cls: True} 

Test() 

Usted podría incluso tener __new__ devolver una referencia a la clase y el uso de un decorador llamarlo:

def instantiate(cls): 
    return cls() 

@instantiate 
class Test(object): 
    def __new__(cls): 
     cls.some_dict = {cls: True} 
     return cls 
Cuestiones relacionadas