Hai un paio di opzioni. Innanzitutto, nota che g nell'esempio non è in realtà un locale per la funzione (cioè non è assegnato all'interno di esso), è un globale (cioè non è stato assegnato a una variabile locale). Ciò significa che verrà esaminato nel modulo in cui è definita la funzione. Questa è una fortuna, poiché non c'è modo di alterare i locali esternamente (a meno di applicare patch al bytecode), poiché vengono assegnati quando la funzione viene eseguita, non prima.
Un'opzione è semplicemente quella di iniettare la funzione nello spazio dei nomi del modulo della funzione. Questo funzionerà, ma interesserà ogni funzione in quel modulo che accede alla variabile, piuttosto che solo una funzione.
Per influenzare solo una funzione, è necessario invece puntare su func_globals da qualche altra parte. Purtroppo, questa è una proprietà di sola lettura, ma si può fare ciò che si vuole ricreando la funzione con lo stesso corpo, ma un diverso namespace globale:
import new
f = new.function(f.func_code, {'g': my_g_function}, f.func_name, f.func_defaults, f.func_closure)
f sarà ora indentico, tranne che sarà per i globali nel dict fornito. Nota che questo riassembla l'intero spazio dei nomi globale - se ci sono variabili che f fa, assicurati di fornire anche loro. Questo è anche abbastanza hacky e potrebbe non funzionare su versioni di python diverse da cpython.
Qual è il tuo obiettivo finale utilizzando questa strana tecnica? Perché non puoi semplicemente definire g() prima di f()? –
Ho provato a pasticciare con lo spazio dei nomi di una funzione in precedenza in fase di esecuzione (per test/mocking) e fallito ... solo FYI. –
cosa diamine è "add_to_locals"? Non sembra esistere per me. 'AttributeError: l'oggetto 'function' non ha attributo 'add_to_locals'' –