Domanda

locals è una funzione incorporata che restituisce un dizionario di valori locali.La documentazione dice:

Avvertimento

Il contenuto di questo dizionario non deve essere modificato;Le modifiche potrebbero non influire sui valori delle variabili locali utilizzate dall'interprete.

Sfortunatamente, exec ha lo stesso problema in Python 3.0.C'è un modo per aggirare questo problema?

Caso d'uso

Prendere in considerazione:

@depends("a", "b", "c", "d", "e", "f")
def test():
    put_into_locals(test.dependencies)

dipende memorizza le stringhe fornite nei suoi argomenti in un elenco test.dependences.Queste stringhe sono chiavi in ​​un dizionario d.Vorrei poter scrivere put_into_locals in modo da poter estrarre i valori d e metterli nella gente del posto.È possibile?

È stato utile?

Soluzione

Ho appena testato exec e funziona in Python 2.6.2

>>> def test():
...     exec "a = 5"
...     print a
...
>>> test()
5

Se stai utilizzando Python 3.x, non funziona più perché i locali sono ottimizzati come array in fase di esecuzione, invece di utilizzare un dizionario.

Quando Python rileva l'"istruzione exec", forzerà Python a cambiare l'archiviazione locale dall'array al dizionario.Tuttavia, poiché "exec" è una funzione in Python 3.x, il compilatore non può fare questa distinzione poiché l'utente avrebbe potuto fare qualcosa come "exec = 123".

http://bugs.python.org/issue4831

Per modificare i locali di una funzione al volo non è possibile senza diverse conseguenze:Normalmente, i locali di funzione non sono archiviati in un dizionario, ma un array, i cui indici sono determinati al tempo di compilazione dalle località conosciute.Questo si scontra almeno con nuovi locali aggiunti da Exec.La vecchia istruzione Exec ha eluso questo, perché il compilatore sapeva che se un dirigente senza Globals/Locali si verificava in una funzione, tale spazio dei nomi sarebbe stato "non ottimizzato", cioènon usando l'array locali.Poiché Exec () è ora una funzione normale, il compilatore non sa cosa può essere legato "Exec" e quindi non può trattare è appositamente.

Altri suggerimenti

Le variabili locali vengono modificate dalle istruzioni di assegnazione.

Se hai chiavi del dizionario che sono stringhe, non renderle anche variabili locali: usale semplicemente come chiavi del dizionario.

Se assolutamente dovere fare in modo che le variabili locali facciano questo.

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 )

Ciò popolerà alcune variabili locali dal tuo dizionario senza fare nulla di magico.

Questo non è possibile.Penso che questo serva a consentire l'ottimizzazione delle prestazioni in un secondo momento.Il bytecode Python fa riferimento ai locals per indice, non per nome;se locals() dovesse essere scrivibile, potrebbe impedire agli interpreti di implementare alcune ottimizzazioni o renderle più difficili.

Sono abbastanza certo che non troverai alcuna API di base che garantisca di poter modificare locals in questo modo, perché se quell'API potesse farlo, neanche locals() avrebbe questa restrizione.

Non dimenticare che tutti i locali devono esistere in fase di compilazione;se fai riferimento a un nome che non è associato a un locale in fase di compilazione, il compilatore presuppone che sia globale.Non puoi "creare" locals dopo la compilazione.

Vedere questa domanda per una possibile soluzione, ma è un trucco serio e davvero non vuoi farlo.

Tieni presente che c'è un problema di base con il tuo codice di esempio:

@depends("a", "b", "c", "d", "e", "f")
def test():
    put_into_locals(test.dependencies)

"test.dependencies" non si riferisce a "f.dependencies" dove f è la funzione corrente;fa riferimento al valore globale effettivo "test".Ciò significa che se usi più di un decoratore:

@memoize
@depends("a", "b", "c", "d", "e", "f")
def test():
    put_into_locals(test.dependencies)

non funzionerà più, poiché "test" è la funzione racchiusa di memoize, non quella di depend.Pitone Veramente ha bisogno di un modo per fare riferimento alla "funzione attualmente in esecuzione" (e alla classe).

Lo memorizzerei in una variabile:

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

E se vuoi testare il tuo dict prima di inserirlo in locals():

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 su MacOS Sierra

Non sono sicuro che sia soggetto alle stesse restrizioni, ma puoi ottenere un riferimento diretto al frame corrente (e da lì al dizionario delle variabili locali) tramite il modulo inspect:

>>> import inspect
>>> inspect.currentframe().f_locals['foo'] = 'bar'
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'foo', 'inspect']
>>> foo
'bar'
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top