2015-04-30 8 views
18

Ho un progetto pitone con la seguente struttura:Perché il formato `from` di Python di un'istruzione import può associare un nome di modulo?

testapp/ 
├── __init__.py 
├── api 
│   ├── __init__.py 
│   └── utils.py 
└── utils.py 

Tutti i moduli sono vuote tranne testapp/api/__init__.py che ha il codice seguente:

from testapp import utils 

print "a", utils 

from testapp.api.utils import x 

print "b", utils 

e testapp/api/utils.py che definisce x:

x = 1 

Ora dalla radice importazione testapp.api:

$ export PYTHONPATH=$PYTHONPATH:. 
$ python -c "import testapp.api" 
a <module 'testapp.utils' from 'testapp/utils.pyc'> 
b <module 'testapp.api.utils' from 'testapp/api/utils.pyc'> 

Il risultato dell'importazione mi sorprende, perché dimostra che la seconda dichiarazione import ha sovrascritto utils. Eppure i documenti affermano che il from statement will not bind a module name:

L'dalla forma non vincola il nome del modulo: si passa attraverso l'elenco degli identificatori, sembra ognuno di loro nel modulo si trovano in fase (1), e associa il nome nello spazio dei nomi locale all'oggetto, quindi trovato .

E infatti, quando in un terminale Io uso una dichiarazione from ... import ..., non siano introdotte nomi di modulo:

>>> from os.path import abspath 
>>> path 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
NameError: name 'path' is not defined 

ho il sospetto che questo ha a che fare con Python, al momento della seconda dichiarazione di importazione, cercando di importare testapp.api.utils che si riferisce a testapp.utils e in mancanza, ma non sono sicuro.

Cosa sta succedendo qui?

+0

Non mi sarei aspettato questo comportamento e sono ansioso di sentire anche la risposta. – ballsatballsdotballs

+0

puoi aggiungere del codice dai vari file utils? –

+1

@NikosM. come ho detto, tutti gli altri file sono vuoti. –

risposta

10

Dalle import system documentation:

Quando un modulo viene caricato utilizzando qualsiasi meccanismo (es importlib API, i import o import-from dichiarazioni, o incorporato __import__()) un legante è collocato nel genitore spazio dei nomi del modulo al sottomodulo oggetto. Ad esempio, se il pacchetto spam ha un sottomodulo foo, dopo l'importazione spam.foo, spam avrà un attributo foo che è associato al sottomodulo.Diciamo che ha la seguente directory struttura:

spam/ 
    __init__.py 
    foo.py 
    bar.py 

e spam/__init__.py ha le seguenti linee in esso:

from .foo import Foo 
from .bar import Bar 

quindi eseguire il seguente mette un nome vincolante per foo e bar nel modulo spam :

>>> import spam 
>>> spam.foo 
<module 'spam.foo' from '/tmp/imports/spam/foo.py'> 
>>> spam.bar 
<module 'spam.bar' from '/tmp/imports/spam/bar.py'> 

Data la familia di Python r regole di binding del nome questo potrebbe sembrare sorprendente, ma in realtà è una caratteristica fondamentale del sistema di importazione. La holding invariante è che se si dispone di sys.modules['spam'] e sys.modules['spam.foo'] (come si farebbe dopo l'importazione di cui sopra), l' deve apparire come l'attributo foo del primo.

Se lo fai from testapp.api.utils import x, l'istruzione import non verrà caricato utils nel namespace locale. Tuttavia, i macchinari di importazione caricheranno nello spazio dei nomi testapp.api nello spazio dei nomi per far funzionare correttamente le importazioni. Succede solo che nel tuo caso, testapp.api è anche lo spazio dei nomi locale, quindi stai ottenendo una sorpresa.

+0

non è stato downvote, ma puoi spiegare di più, è non mi è chiaro –

+0

Se si utilizza il modulo 'from', nessun nome viene importato nello spazio dei nomi locale. Stai dicendo che sono comunque legati se si riferiscono a qualcosa? Se fosse vero, allora 'percorso = 1; da os.path import abspath; percorso' non dovrebbe valutare in '1'. –

+2

@CeasarBautista: il nome del modulo non è associato nello spazio dei nomi * local *, ma * è * associato nello spazio dei nomi del pacchetto. È solo che in questo caso, quelli sono lo stesso spazio dei nomi. – user2357112