2016-04-17 2 views
1

En Python 2 (pas sûr de 3), le dictionnaire local n'est mis à jour que lorsque vous appelez réellement locals(). Ainsi, par exempleComment puis-je forcer la mise à jour du dictionnaire local Python() d'un autre cadre de pile?

l=locals() 
x=2 
l['x'] 

échoue parce que l n'a pas le « x » clé, mais

l=locals() 
x=2 
locals() 
l['x'] 

retours 2.

Je cherche un moyen de forcer une mise à jour de la dictionnaire local, mais l'astuce est que je suis dans un cadre de pile différente. Ainsi, par exemple Je cherche à faire

l=locals() 
x=2 
force_update() 
l['x'] 

et je dois écrire la fonction force_update(). Je sais que de cette fonction je peux obtenir le cadre parent via inspect.currentframe().f_back, et même les parents par défaut (non mis à jour) via inspect.currentframe().f_back.f_locals, mais comment puis-je forcer une mise à jour?

Si cela semble alambiqué, mon but principal est d'écrire une fonction qui est un raccourci pour "{some} string".format(**dict(globals(),**locals())) donc je ne dois pas taper à chaque fois, et peut faire fmt("{some} string"). Ce faisant, je rencontre le problème ci-dessus.

Éditer: Avec Martjin répondez ci-dessous, ci-dessous est essentiellement la solution que je recherchais. On pourrait jouer avec exactement comment ils obtiennent le cadre de la pile de l'appelé, ici je le fais via partial.

from functools import partial 
from inspect import currentframe 

fmt = partial(lambda s,f: s.format(**dict(globals(),**f.f_locals)),f=currentframe()) 
x=2 
print fmt("{x}") #prints "2" 
+0

Dans votre éditeur, vous pouvez définir un raccourci, un extrait, ou tout ce que l'éditeur appelle pour développer '.format (** dict (globals(), ** locals()))'. Beaucoup d'éditeurs soutiennent quelque chose comme ça. –

+0

Pourquoi utilisez-vous '' {{some} string ".format (** dict (globals(), ** locals()))' tant de fois dans votre code? Est-ce que votre chaîne de format a vraiment besoin d'accéder à toutes les variables dans les espaces de noms locaux et globaux? – emeraldemon

+0

Si vous pouvez obtenir le cadre parent (voir aussi 'sys._getframe (1)') alors pourquoi avez-vous besoin de 'globals()' et 'locals()'? – cdarke

Répondre

1

simplement accès f_locals sur un objet cadre déclenche la copie, donc l'utilisation inspect.currentframe().f_back.f_localsest assez.

Voir la frame_getlocals() function dans la mise en œuvre frameobject.c:

static PyObject * 
frame_getlocals(PyFrameObject *f, void *closure) 
{ 
    PyFrame_FastToLocals(f); 
    Py_INCREF(f->f_locals); 
    return f->f_locals; 
} 

PyFrame_FastToLocals est la fonction utilisée pour copier les données du tableau interal suivi des valeurs des sections locales à un dictionnaire. frame_getlocals est utilisé pour implémenter le descripteur frame.f_locals (une propriété); voir le frame_getsetlist definition.

La fonction PyFrame_FastToLocalsWithError utilisée ci-dessus est exactement ce que locals() utilise pour produire le même dictionnaire (par wrapping le PyEval_GetLocals function).

+0

Aha! Merci. J'ai réussi à trouver 'currentframe(). F_locals' mais je ne me rends pas compte que cela force exactement la mise à jour que je cherchais. – marius

+0

Oui, sachez que le contraire ne se produit pas - il n'y a aucun moyen de mettre à jour les variables rapides en changeant les valeurs dans les sections locales. – jsbueno

+0

cela fonctionne pour python 3 ou supérieur? –