2010-12-14 10 views
10

Sono rimasto sorpreso di scoprire cheConfermando la differenza tra import * e da xxx import *

import foo 

e

from foo import * 

avevano effetti diversi sui membri globali. Volevo confermare che i miei esperimenti sono il comportamento corretto.

Nel primo esempio, la modifica di un membro nel modulo pippo rifletterà in tutto il codice che importa pippo. Tuttavia, la modifica di quel membro nel caso successivo sembra influire solo sul file in cui è stato importato. In altre parole, l'utilizzo dell'approccio successivo darà ad ogni file di importazione la propria copia dei membri da parte di foo.

il comportamento che voglio è quello di avere accesso a foo.x da tutti i file, in grado di cambiare da tutti i file, e che hanno il cambiamento riflette in tutti i file (un vero globale se si vuole).

risposta

14

Sì, le tue osservazioni sono corrette. Questa è una conseguenza del modo in cui funziona il binding in Python.

Quando uno fa

import foo 

poi foo diventa un nome globale che fa riferimento al modulo di foo. Quando si fa

foo.bar = 7 

Poi è seguito il riferimento e l'oggetto foo viene caricato. Quindi 7 è memorizzato nell'attributo bar.

Quando un altro modulo importa foo, estrae semplicemente l'oggetto da sys.modules['foo'] e ottiene il valore modificato.

Quando si fa

from foo import bar 

globals()['bar'] è impostato riferimento foo.bar. Quando si fa tardi

bar = 7 

globals()['bar'] non fa riferimento foo.bar ma fa riferimento a una copia di 7. Cioè, il legame originale nella portata globale del modulo di importazione è semplicemente sostituito.

Nel primo esempio, uno modifica gli attributi di un oggetto archiviato in sys.modules e sarà comune a tutti i moduli che lo hanno importato. Nel secondo esempio, uno sta modificando l'ambito globale del modulo di importazione.

Se uno era di fare qualcosa sulla falsariga di

from foo import fobaz 
fobaz.foobar = 7 

Poi che il cambiamento sarebbe propagherà ad altri moduli di importazione perché uno non sovrascrivere il riferimento globale ma seguente esso per modificare un attributo dell'oggetto a cui punta. Quindi, in sostanza, dovresti essere in grado di modificare gli oggetti mutabili fintanto che non sovrascrivi il binding globale.

Penso che una cosa del genere sia la cosa più vicina che riuscirai a ottenere in modo pulito in un vero globale in python. Come lingua, attribuisce grande importanza agli spazi dei nomi.

+0

Wow, non lo sapevo. Bella risposta. – invert

4

Considerando che le variabili globali sono generalmente considerate come una cosa negativa, sospetto che una variabile "vera globale" sarebbe una cosa estremamente negativa.

Un altro modo per ottenere un comportamento simile consiste nell'utilizzare gli attributi di ambito di classe in un oggetto singleton e importarlo. Quindi è più chiaro da dove ottieni la variabile "globale".

+0

Questo è un buon punto, grazie per la risposta. –