2015-04-30 13 views
18

Mam projektu Pythona o następującej strukturze:Dlaczego forma Pythona "z" instrukcji import może wiązać nazwę modułu?

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

Wszystkie moduły są puste z wyjątkiem testapp/api/__init__.py, który posiada następujący kod:

from testapp import utils 

print "a", utils 

from testapp.api.utils import x 

print "b", utils 

i testapp/api/utils.py który definiuje x:

x = 1 

Teraz z katalogu głównego importuję 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'> 

Wynik importu zaskakuje mnie, ponieważ pokazuje, że drugi import oświadczenie jest zastępowane utils. Jeszcze docs stwierdzić, że from statement will not bind a module name:

FROM formularza nie wiąże nazwę modułu: to przechodzi listy identyfikatorów, wygląda każdy z nich się w module znaleziony w kroku (1), i wiąże nazwę w lokalnej przestrzeni nazw z obiektem, który został znaleziony.

I rzeczywiście, kiedy w terminalu używam from ... import ... oświadczenie, bez nazwy modułów są wprowadzane:

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

I podejrzewam, że ma do czynienia z Pythona, w czasie drugiej instrukcji import, próbuje importować testapp.api.utils, który odnosi się do testapp.utils i nie, ale nie jestem pewien.

Co się tutaj dzieje?

+0

Nie spodziewałbym się takiego zachowania i nie mogę się doczekać odpowiedzi. – ballsatballsdotballs

+0

możesz dodać kod z różnych plików utils? –

+1

@NikosM. jak już wspomniałem, wszystkie pozostałe pliki są puste. –

Odpowiedz

10

Z import system documentation:

Gdy modułem jest ładowany za pomocą dowolnego mechanizmu (np importlib API, się import lub import-from stwierdzenia, lub wbudowanych w __import__()) wiążącą umieszcza się w nadrzędnej obszar nazw modułu do obiektu pododdziału obiektu . Na przykład, jeśli pakiet spam ma submoduł foo, po zaimportowaniu spam.foo, spam będzie miał atrybut foo, który jest związany z modułem częściowym.Powiedzmy, że masz następujący katalog strukturę:

spam/ 
    __init__.py 
    foo.py 
    bar.py 

i spam/__init__.py posiada następujące linie w nim:

from .foo import Foo 
from .bar import Bar 

następnie wykonując następujące umieszcza nazwę wiązania foo i bar w moduł 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'> 

Biorąc pod uwagę rodzinę Pythona Zasady wiążące się z nazwami mogą wydawać się zaskakujące, ale jest to podstawowa cecha systemu importu. Niezmienne jest to, że jeśli masz sys.modules['spam'] i sys.modules['spam.foo'] (tak jak po powyższym imporcie), to musi on pojawić się jako atrybut tego pierwszego.

Jeśli wykonasz from testapp.api.utils import x, instrukcja import nie załaduje utils do lokalnej przestrzeni nazw. Jednak mechanizm importu zostanie umieszczony w przestrzeni nazw utils, aby dalsze importowanie działało poprawnie. Zdarza się, że w twoim przypadku testapp.api jest również lokalną przestrzenią nazw, więc robisz niespodziankę.

+0

nie została odrzucona, ale możesz wyjaśnić więcej, to jest nie jest dla mnie jasne –

+0

Jeśli użyjesz formularza "od", żadne nazwy nie zostaną zaimportowane do lokalnej przestrzeni nazw. Mówisz, że oni są związani tak czy inaczej, jeśli odnoszą się do czegoś? Jeśli to prawda, to 'ścieżka = 1; z abpath importu os.path; ścieżka "nie powinna mieć wartości" 1 ". –

+2

@CeasarBautista: Nazwa modułu nie jest powiązana z * lokalnym * obszarem nazw, ale * jest * powiązana w przestrzeni nazw pakietu. Chodzi tylko o to, że w tym przypadku są to te same obszary nazw. – user2357112

Powiązane problemy