2010-04-24 9 views
8

Voici un exemple très simple de ce que je suis en train de se déplacer:classe __init__ (pas exemple __init__)

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

Le problème est que je ne peux pas se référer à essai pendant qu'il est encore en cours de définition

Normalement, je ferais juste ceci:

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

Mais je ne crée jamais une instance de cette classe. C'est vraiment juste un conteneur pour contenir un groupe de fonctions et de données connexes (j'ai plusieurs de ces classes, et je leur passe des références, donc est nécessaire pour que Test soit sa propre classe)

question est, comment pourrais-je me référer à Test alors qu'il est en cours de définition, ou y at-il quelque chose de similaire à __init__ qui est appelé dès que la classe est définie? Si possible, je veux que self.some_dict = {Test: True} reste dans la définition de la classe. Ceci est la seule façon que je sais comment faire cela jusqu'à présent:

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

"Le problème est que je ne peux pas me référer à Test tant qu'il est encore en cours de définition". Alors? De quel type de référence avez-vous besoin ** pendant la définition **? La réponse standard est None: la définition de classe est stable, cohérente et invariante. ** Comportement ** peut changer. La définition ne devrait pas changer. Qu'essayez-vous de faire avec cette entreprise de «définition variable»? –

+0

La définition ne change pas. J'ai juste besoin d'une référence à la classe, et à des fins d'organisation, je préférerais que je fixe cette référence lorsque la classe est en cours de définition. – Ponkadoodle

+0

Je comprends ce que vous essayez de faire, mais je ne comprends pas pourquoi vous essayez de le faire de cette façon et ce que vous cherchez à accomplir. Pouvez-vous élaborer un peu? Cela ressemble plus à une architecture qu'à un "comment est-ce que je peux python ...?" question à moi. – Aea

Répondre

12

La classe n'existe en fait pas pendant qu'elle est en cours de définition. La façon dont l'instruction class fonctionne est que le corps de l'instruction est exécuté, en tant que bloc de code, dans un espace de noms distinct. À la fin de l'exécution, cet espace de noms est transmis à la métaclasse (tel que type) et la métaclasse crée la classe en utilisant l'espace de noms en tant qu'espace d'attributs.

De votre description, il fait pas son nécessaire pour que Test soit une classe. Il semble que ce devrait être un module à la place. some_dict est un global - même s'il s'agit d'un attribut de classe, il n'y a qu'un tel attribut dans votre programme, donc ce n'est pas mieux que d'avoir un global - et toutes les méthodes de classe que vous avez dans la classe peuvent être des fonctions.

Si vous voulez vraiment être une classe, vous disposez de trois options: définir le dict après avoir défini la classe:

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

Utilisez un décorateur de classe (en Python 2.6 ou version ultérieure):

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

@set_some_dict 
class Test: 
    some_dict = {} 

Ou utilisez un métaclasse:

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 pour une réponse détaillée –

+0

Ça * pourrait * être un module, mais je préférerais que ce soit une classe. Si c'était dans un module séparé, je devrais faire un peu de réarrangement pour empêcher les importations circulaires. En outre, je devrais avoir 20 onglets ouverts lors de l'édition de mon projet si toutes ces classes étaient dans des fichiers différents. En tout cas, merci de me parler de Metaclasses. – Ponkadoodle

+0

le décorateur est une approche cool –

4

Vous pouvez ajouter l'attribut some_dict après la définition de la classe principale.

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

C'est le moyen de le faire. – PaulMcG

+0

D'accord - c'est la bonne réponse. –

0

Vous pouvez également utiliser une méta-classe (fonction ici, mais il y a d'autres façons) :

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

premier exemple de Thomas est très bon, mais voici une façon plus Pythonic de faire la même chose.

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

J'ai essayé d'utiliser des classes de cette façon dans le passé, et il obtient assez rapidement laid (par exemple, toutes les méthodes devront être des méthodes de classe ou des méthodes statiques, et vous vous rendrez compte probablement par la suite que vous voulez définir certaines méthodes spéciales, pour lesquelles vous devrez commencer à utiliser des métaclasses).Cela pourrait rendre les choses beaucoup plus faciles si vous utilisez simplement des instances de classe à la place - il n'y a pas vraiment d'inconvénients.

A (aspect bizarre) alternative à ce que d'autres ont suggéré: vous pouvez utiliser __new__:

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

Test() 

Vous pourriez même avoir __new__ retourner une référence à la classe et utiliser un décorateur pour l'appeler:

def instantiate(cls): 
    return cls() 

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