2015-01-28 13 views
5

Un oggetto codice generato dal compilatore Python contiene una tupla di costanti utilizzate nelle istruzioni (denominate co_consts) e anche una tupla contenente nomi (denominati co_names).Perché Python VM ha co_names invece di usare solo co_consts?

Perché disporre di due elenchi distinti? Non sarebbe più semplice usare solo co_consts anche per i nomi?

+0

Solo per verificare, stai parlando di cpython corretto? Quale versione? –

+0

@GamesBrainiac: 'co_names' è usato in cpython sia in 2 che in 3 e in pypy. Non sono sicuro di altre implementazioni perché non le uso. – 6502

+0

Non ricordo molto bene, ma sono abbastanza sicuro che abbia qualcosa a che fare con il decapaggio. –

risposta

6

Considerare la seguente funzione.

def f(x): 
    x += n 
    return x * 4 

Qui x è un nome locale, il suo valore può cambiare. 4 è una costante. Il suo valore non cambierà mai. Tuttavia, è ancora un oggetto ed è meglio memorizzarli nella cache piuttosto che creare un nuovo oggetto ogni volta che è necessario. Infine, n è un riferimento globale. La stringa "n" viene memorizzata dalla funzione in modo che possa essere utilizzata come chiave per recuperare n dal contesto globale della funzione.

>>> f.__code__.co_nlocals # just 1 (for x) 
1 
>>> f.__code__.co_consts 
(None, 4) 
>>> f.__code__.co_names 
('n',) 
>>> "n" in f.__globals__ and globals() is f.__globals__ 
True 

La ragione per mantenere i nomi e const separata è a fini di introspezione. L'unica vera ragione per unire le tuple sarebbe l'efficienza della memoria, anche se questo ti permetterebbe di ottenere solo un oggetto e un puntatore per ogni funzione. Considera la seguente funzione.

def g(): 
    return "s" * n 

Se la tupla contenente const è stato fuso con i nomi tupla contenente allora (non il VM) non sarebbe in grado di dire che i valori sono stati per globali di accesso e quali erano le costanti della funzione.

1

So che questa risposta è come 11 mesi fuori moda ma dal mio armeggiare sembra il seguente sta accadendo

Per accedere co_names in bytecode, uno usa LOAD_GLOBAL (indice nomi co) e questo spinge un riferimento alla co_names desiderati sulla pila, ad esempio alla sua indiretta

Per accedere co_consts in bytecode, uno usa LOAD_CONST (indice const co) e questo spinge il valore effettivo memorizzato le co_consts desiderati sulla pila, ad esempio alla sua diretta

i Non sono sicuro che abbia un rilevamento diretto a livello di un pitone, ma a livello di bytecode è un profitto nd difference

+0

Ovviamente c'è una grande differenza poiché "LOAD_CONST" carica una costante nello stack mentre "LOAD_GLOBAL" invece fa una ricerca. Tuttavia il nome globale ** è solo un oggetto 'str' di Python e potrebbe essere inserito nell'elenco' co_consts' invece di 'co_names'. Il punto della mia domanda è "perché usare due elenchi quando si utilizza solo il comando' co_const' sarebbe stato sufficiente? "... Non sono ** ** dicendo che l'opcode' LOAD_GLOBAL' non è necessario perché abbiamo 'LOAD_CONST' , ma solo che i due avrebbero potuto usare la stessa lista invece di avere due liste. Qualsiasi opcode che si riferisca a un ** nome ** avrebbe potuto usare 'op_consts'. – 6502

+0

Non conosco il motivo per cui è stato progettato in questo modo, ma i 2 istruttori spingono diversi tipi di dati nello stack (valore vs riferimento) –

+0

Se avessi entrambi i nomi e le sonde unite avresti ancora bisogno di qualche tipo di istruzione da dire la VM sia che si tratti di un riferimento o di un valore, quindi sono 2 istruzioni per carico, ad esempio loadconstname, setconstnametype, e non è veloce come una singola chiamata, in più se hai idjuts (eg me) che incasina con bytecode è più sicuro dalla VM prospettiva –

Problemi correlati