2010-08-06 2 views
2

Je suis en train de se débarrasser de exec dans un code similaire à ceci:Création dynamique de terrain de classe avant les machines metaclass

class A(object): 
    for field in ['one', 'two', 'three']: 
     exec '%s = "%s value"' % (field, field) 

... de telle sorte que:

>>> A.one 
'one value' 
>>> A.two 
'two value' 
>>> A.three 
'three value' 

EDIT: et aussi l'exigence mentionnée dans le sujet est remplie, c.-à-d. A.one est 'one value', avant que A soit instancié (à ne pas confondre avec A() instancié).

Y a-t-il un moyen?

+0

Pouvez-vous expliquer ce que le titre a à voir avec la question? –

+0

Ceci est icky. Pourquoi voulez-vous le faire? – katrielalex

+0

@gnibbler Oui. J'essaye de faire cela avant que la classe soit instanciée. Ainsi, la métaclasse appelée à se référer à A fonctionne déjà sur ces champs créés dynamiquement. – dhill

Répondre

2
>>> values = 'one', 'two', 'three' 
>>> A = type('A', (object,), {i: i + ' value' for i in values}) 
>>> A.one 
'one value' 
>>> A.three 
'three value' 
2

Utilisez the setattr function.

class A(object): 
    pass 

for field in ['one', 'two', 'three']: 
    setattr(A, field, field + ' value') 
+0

Je devrais avoir répété l'exigence du sujet ... bien que maintenant je ne suis pas sûr si cela tient pour la version avec 'exec'. – dhill

+0

Je l'ai testé et la version avec 'exec' est exécutée avant' __metaclass __.__ new __() '... J'ai aussi essayé de mettre setattr() dans' A' avant de poster, mais cela n'a pas fonctionné car 'A' n'est pas défini encore. – dhill

1

Vous dites que vous voulez générer quelque chose de manière dynamique que la métaclasse peut traiter. Il existe un moyen très simple d'y parvenir sans avoir recours au hackery comme exec. Tout ce que vous avez à faire est de penser différemment: modifiez la métaclasse pour que les noms soient générés là. Si vous ne souhaitez pas modifier la métaclasse existante, vous pouvez la sous-classer.

+0

me battre de 33 secondes mais je vais passer le temps supplémentaire pour la qualité;) – aaronasterling

+0

Cela fait le travail, il mérite +1, mais je suis toujours là en attente dans l'espoir que vous pouvez le faire en trois lignes claires comme l'original code et sans 'exec'. Si seulement il y avait un moyen d'appeler '=' (déclarations ...). – dhill

+1

Si vous ignorez la définition de la métaclasse, il n'y a que deux lignes et elles sont plus claires que l'original. Vous pouvez * le faire trivialement dans le même nombre de lignes que votre original sans utiliser exec, mais vous ne voulez vraiment pas descendre cette route [dans un corps de classe que vous pouvez assigner à 'vars()/locals()' et contrairement à assigner à 'locals()' dans une fonction cela fonctionnera probablement, probablement, cette semaine]. 'vars() [field] ="% s value "% field' – Duncan

2

Je venais hériter de la métaclasse et de le faire il

class MyMetaClass(MetaClass): 
    def __new__(meta, classname, baseclasses, classdict): 
     fields = classdict['__myfields__'] 
     for field in fields: 
      classdict[field] = field + ' value' 
     del classDict['__myfields__'] 
     MetaClass.__new__(meta, classname, baseclasses, classdict) 

Ensuite, vous pouvez juste faire:

class A(object): 
    __metaclass__ = MyMetaClass 
    __myfields__ = ['one', 'two', 'three'] 
0

Permettez-moi de cette préface en disant que c'est incroyablement hackish mais élimine l'exec. Nous ne faisons que coller les attributs sur le cadre de la pile courante lorsque le code de l'instruction de classe est en cours d'exécution. Il est seulement garanti de travailler sur CPython et il y a des avertissements contre le faire dans le manuel. Je recommande fortement que vous allez avec Dunnans solution de métaclasse.

import sys 

class A(object): 
    for field in ['one', 'two', 'three']: 
     sys._getframe().f_locals[field] = field + ' value' 
1

Cela fonctionne aussi et je pense que c'est une fin heureuse ...

class A(object): 
    for a in ['one', 'two', 'three']: 
     locals().update({a: a + ' value'}) 

Et pour tous ceux qui cherchent l'expression d'affectation en Python, c'est dans la même humeur que aaronasterling réponse :):

http://code.activestate.com/recipes/202234-assignment-in-expression/

+0

+1 pour me rappeler de 'locals' – aaronasterling

+0

Ou si vous vouliez un doublon:' vars(). Update ((champ, champ + "valeur") pour le champ dans ('un', 'deux', 'trois')) 'ick – Duncan

Questions connexes