2009-06-19 9 views
19

Y at-il un moyen de référencer un nom de classe à partir de la déclaration de classe? Voici un exemple:Définition de classe auto-référencée en python

class Plan(SiloBase): 
    cost = DataField(int) 
    start = DataField(System.DateTime) 
    name = DataField(str) 
    items = DataCollection(int) 
    subPlan = ReferenceField(Plan) 

j'ai un métaclasse qui lit cette information et fait une certaine configuration, et la classe de base met en œuvre des trucs d'économie commune. J'aimerais pouvoir créer des définitions récursives comme celle-ci, mais jusqu'ici dans mon expérimentation j'ai été incapable d'obtenir l'effet que je désire, en courant habituellement dans une erreur "Plan n'est pas défini". Je comprends ce qui se passe, le nom de la classe n'est pas dans la portée de la classe.

Répondre

8

j'ai un métaclasse qui lit cette information et fait quelques configuration

La plupart des cadres qui utilisent métaclasses fournissent un moyen de résoudre ce problème. Par exemple, Django:

subplan = ForeignKey('self') 

Google App Engine:

subplan = SelfReferenceProperty() 

Le problème avec des solutions comme clouant une propriété supplémentaire sur la suite ou en utilisant __new__ est que la plupart des métaclasses ORM attendent les propriétés de la classe d'exister au moment où la classe est créée.

+1

Super que vous avez mentionné Google App Engine ainsi! +1 –

+1

Dans Google App Engine - DB l'a, mais pas le NDB. Pour voir comment faire ceci dans le NDB regardez ici: http://stackoverflow.com/questions/3531936/selfreferenceproperty-question – Brad

22

Essayez ceci:

class Plan(SiloBase): 
    cost = DataField(int) 
    start = DataField(System.DateTime) 
    name = DataField(str) 
    items = DataCollection(int) 

Plan.subPlan = ReferenceField(Plan) 

OU utiliser __new__ comme ceci:

class Plan(SiloBase): 

    def __new__(cls, *args, **kwargs): 
     cls.cost = DataField(int) 
     cls.start = DataField(System.DateTime) 
     cls.name = DataField(str) 
     cls.items = DataCollection(int) 
     cls.subPlan = ReferenceField(cls) 
     return object.__new__(cls, *args, **kwargs) 
+0

génial, cela fait exactement ce que je veux, et ce n'est pas un hack énorme. J'essaye toujours d'envelopper ma tête autour de cette chose dynamique, haha ​​ – pedlar

0

Non, vous ne pouvez pas faire cela. Pensez à ce qui se passerait si vous avez fait cela:

OtherPlan = Plan 
other_plan = OtherPlan() 

à l'instanciation de other_plan, quel est le nom de la classe?

Quoi qu'il en soit, ce genre de chose est mieux fait dans la méthode __new__, qui prend un cls paramètre se référant à la classe.

1

Je comprends ce qui se passe, le nom de la classe n'est pas portée intérieur de la classe.

Pas exactement. Le nom de la classe n'est pas encore défini lors de la définition de son contenu (par exemple, portée).

Questions connexes