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?

Était-ce utile?

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.

Voir

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'
scroll top