De toute façon de modifier le dictionnaire de la population locale?
-
11-09-2019 - |
Question
locals
est une fonction intégrée qui renvoie un dictionnaire de valeurs locales. La documentation dit:
Avertissement
Le contenu de ce dictionnaire devrait pas être modifié; les changements ne peuvent affecter les valeurs des variables locales utilisé par l'interpréteur.
Malheureusement, exec a le même problème en Python 3.0. Est-il possible autour de ce?
Cas d'utilisation
Considérez:
@depends("a", "b", "c", "d", "e", "f")
def test():
put_into_locals(test.dependencies)
dépend stocke les chaînes fournies dans ses arguments dans une liste test.dependences
. Ces chaînes sont clés dans un dictionnaire d
. Je voudrais être en mesure de pouvoir écrire put_into_locals
afin que nous puissions tirer les valeurs de d
et les mettre dans la population locale. Est-ce possible?
La solution
Je viens de tester exec et il fonctionne en Python 2.6.2
>>> def test():
... exec "a = 5"
... print a
...
>>> test()
5
Si vous utilisez Python 3.x, il ne fonctionne plus parce que les habitants sont optimisés comme un tableau à l'exécution, au lieu d'utiliser un dictionnaire.
Lorsque Python détecte la « instruction exec », il forcera Python pour passer le stockage local du tableau à dictionnaire. Cependant, depuis « exec » est une fonction Python 3.x, le compilateur ne peut pas faire cette distinction car l'utilisateur aurait pu faire quelque chose comme « exec = 123 ».
http://bugs.python.org/issue4831
Pour modifier les habitants d'une fonction sur la mouche n'est pas possible sans plusieurs conséquences: normalement, les habitants de la fonction ne sont pas stockés dans un dictionnaire, mais un tableau, dont indices sont déterminés au moment de la compilation des lieux connus. cette collision au moins avec de nouveaux locaux ajoutés par exec. L'ancienne instruction exec contournée, parce que la compilateur savait que si un exec sans GLOBALS / args sections locales se sont produits dans un fonction, cet espace serait « Unoptimized », à savoir ne pas utiliser la tableau habitants. Depuis exec () est maintenant fonction normale, le compilateur ne savoir ce que « exec » peut être lié, et ne peut donc pas traiter est spécialement.
Autres conseils
Les variables locales sont modifiées par les instructions d'affectation.
Si vous avez les clés de dictionnaire qui sont des chaînes, s'il vous plaît ne les rend pas aussi variables locales -. Il suffit de les utiliser les touches comme dictionnaire
Si vous absolument doit ont des variables locales le faire.
def aFunction( a, b, c, d, e, f ):
# use a, b, c, d, e and f as local variables
aFunction( **someDictWithKeys_a_b_c_d_e_f )
Cela renseignera certaines variables locales de votre dictionnaire sans faire quoi que ce soit magique.
Ceci est impossible. Je pense que cela est de permettre l'optimisation des performances plus tard. bytecode Python fait référence à la population locale par index, et non par son nom; si la population locale () devait être accessible en écriture, il pourrait empêcher les interprètes de mettre en œuvre certaines optimisations, ou les rendre plus difficiles.
Je suis assez certain que vous n'allez trouver une API de base qui garantit que vous pouvez modifier les habitants comme ça, parce que si cette API pouvait le faire, les habitants () auraient pas cette restriction soit.
Ne pas oublier que toutes les sections locales doivent exister au moment de la compilation; si vous faites référence à un nom qui n'est pas lié à une section locale à la compilation, le compilateur suppose qu'il est un global. Vous ne pouvez pas « créer » la population locale après la compilation.
Je le stocker dans une variable:
refs = locals()
def set_pets():
global refs
animals = ('dog', 'cat', 'fish', 'fox', 'monkey')
for i in range(len(animals)):
refs['pet_0%s' % i] = animals[i]
set_pets()
refs['pet_05']='bird'
print(pet_00, pet_02, pet_04, pet_01, pet_03, pet_05 )
>> dog fish monkey cat fox bird
Et si vous voulez tester votre dict avant de le mettre dans les locaux ():
def set_pets():
global refs
sandbox = {}
animals = ('dog', 'cat', 'fish', 'fox', 'monkey')
for i in range(len(animals)):
sandbox['pet_0%s' % i] = animals[i]
# Test sandboxed dict here
refs.update( sandbox )
Python 3.6.1 sur Mac OS Sierra
Je ne sais pas si elle est soumise aux mêmes restrictions, mais vous pouvez obtenir une référence directe à la trame courante (et à partir de là, le dictionnaire des variables locales) à travers le module inspecter:
>>> import inspect
>>> inspect.currentframe().f_locals['foo'] = 'bar'
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'foo', 'inspect']
>>> foo
'bar'