2010-10-11 13 views
8

main.py:Python: dlaczego importowany moduł nie może odwoływać się do innego importowanego modułu?

import subone 
import subtwo 

subone.py:

a = 'abc' 

subtwo.py:

print subone.a 

Running python main.py rzuca NameError: name 'subone' is not defined. Spodziewałem się, że wydrukuje "abc".

Refaktoryzacja go używać fromimport i zajęcia nie pomaga:

main.py:

from subone import * # Only using from X import * for example purposes. 
from subtwo import * 

print 'from main.py:', a.out 

subone.py:

class A: 
    out = 'def' 

a = A() 

subtwo. py:

# This throws NameError: name 'a' is not defined 
print a.out 

# This throws NameError: name 'A' is not defined 
b = A() 
print b.out 

ale będzie print 'z main.py: def'. (Działa również przy użyciu import).

Dlaczego to działa w ten sposób? Wygląda na to, że po zaimportowaniu subone powinien on być dostępny pod numerem subtwo.

Czy to dlatego, że złe programowanie polega na tym, że importowane moduły są od siebie zależne, bez przechodzenia przez ich "macierzysty" moduł? Czy istnieje inny, standardowy sposób, aby to zrobić?

Aktualizacja:

teraz rozumiem, że pierwszy przykład nie zadziała, ponieważ linia print subone.a nie rozpoznaje nazwy subone, nie będąc w subtwo „s nazw (choć to w main.py” s) i jest wywoływany z poziomu modułu subtwo. Można to naprawić, używając import subone na górze subtwo.py - nie będzie on ponownie ładował modułu, ale doda go do przestrzeni nazw subtwo, aby można było z niego korzystać subtwo.

Ale co o tym:

main.py:

from subone import Nugget 
from subtwo import Wrap 

wrap = Wrap() 
print wrap.nugget.gold 

subone.py:

class Nugget: 
    gold = 'def' 

subtwo.py:

class Wrap: 
    nugget = Nugget() 

Myślę, że skoro Wrap i Nugget są zarówno ładowane bezpośrednio do main „nazw s, które używają main” nazw s oraz być w stanie odwołać się do siebie, ale to rzuca NameError: name 'Nugget' is not defined. TO JEST, ponieważ Wrap jest oceniane/sprawdzane od w przestrzeni nazwsubtwo PRZED załadowaniem do przestrzeni nazw main?

+4

Twój enkapsulacji wydaje się naprawdę złamane ... – Daenyth

+0

trzeba odnośnika leksykalny scopingu. Podstawową ideą jest to, że kod ma dostęp do tego, co "widzi" w kodzie źródłowym. to, co dzieje się w czasie wykonywania, nie ma z tym nic wspólnego. – aaronasterling

Odpowiedz

6

Jeśli zmodyfikowany subtwo.py ten sposób to będzie działać

import subone 
print subone.a 

Kiedy robisz subone.a w subtwo.py, którą próbujesz otworzyć subone namespace w subtwo.py aw przestrzeń nazw "subone", powinien istnieć atrybut "a".

Kiedy to robisz - importuj subone w subtwo.py, a następnie podporządkowana jest dodawana do przestrzeni nazw i podporządkowanej przestrzeni nazw ma atrybut a. więc subone.a zadziała.

Proponuję również, aby grać z dir(), aby zobaczyć, jak dodawane są przestrzenie nazw.

W subtwo.py, można wykonać następujące czynności:

print dir() 
import subone 
print dir() 
print subone.a 

Podobnie, spróbuj dodać „dir print()” przed i po swoim sprawozdaniu przywozowych i idea powinna stać się dla ciebie jasne.

„import x” dodaje „x” do obecnych modułów nazw podczas „od x import *” będzie dodać wszystkie poziomie modułu atrybutów bezpośrednio do bieżącej przestrzeni nazw modułu

Więc w powyższy pierwszy przykład main.py, subone.py i subtwo.py, przestrzeń nazw w main.py będzie zawierać "subone" i "subtwo", a subtwo.py będzie mieć pustą przestrzeń nazw i nie będzie mieć dostępu do subone.a.

[Edycja: Niektóre więcej wyjaśnień] rozważyć następujące pliki: main.py

print "Before importing subone : ", dir() 
import subone 
print "After importing subone and before importing subtwo: ", dir() 
import subtwo 
print "After importing subone and subtwo: ", dir() 

subone.py

a = 'abc' 

subtwo.py

print dir() 
import subone 
print "module level print: ", subone.a 
print dir() 
def printX(): 
    print subone.a 

A wyjście z działania main.py:

Before importing subone : ['__builtins__', '__doc__', '__file__', '__name__', '__package__'] 
After importing subone and before importing subtwo: ['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'subone'] 
['__builtins__', '__doc__', '__file__', '__name__', '__package__'] 
module level print: abc 
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'subone'] 
After importing subone and subtwo: ['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'subone', 'subtwo'] 

Niektóre Obserwacje

  1. można zauważyć, że importowanie modułu subtwo.py, instrukcja drukowania jest wykonywane natychmiast.
  2. Tak więc, gdy subone i subtwo są importowane w pliku main.py, rozszerzony jest obszar nazw main.py.
  3. To nie znaczy, że przestrzeń nazw subtwo zostanie zwiększona. więc "a" jest dostępne tylko w main.py przez subone.a
  4. Kiedy robimy import subone w subtwo.py to przestrzeń nazw subtwo jest powiększona o podnoście a atrybut a modułu subone jest dostępny w subtow.py przez podjednostkę .a
+0

Jest to bardzo pomocne. dir() naprawdę wyjaśnia mi pewne rzeczy. Moje jedyne pytanie (jak skomentowałem poniżej) jest takie, że jeśli "from x import *" dodaje wszystkie atrybuty na poziomie modułu bezpośrednio do bieżącej przestrzeni nazw, to dlaczego te atrybuty nie mają dostępu do siebie? –

+1

Ten import nie zmienia zakresu atrybutów, a jedynie kopiuje ich definicję do zakresu lokalnego. –

+0

@willell: Ignacio Vazquez-Abrams ma rację. Powinienem być bardziej dokładny. To nie jest to samo, co kopiowanie kodu, jak to się dzieje w przypadku #include w "C". Zaimportowane moduły są już załadowane i ocenione. jeśli posiadasz polecenie print w importowanym module, zostałoby to już ocenione. – pyfunc

2

Przestrzeń nazw subtwo będzie całkowicie pusta, chyba że zaimportujesz do niej subone.

miarę praktyk programowania, subone i subtwo może zależeć od siebie, jeśli jest taka potrzeba, po prostu trzeba wyraźnie powiązać je (zawierające import)

+0

Okay, ale dlaczego nie działa, nawet przy użyciu opcji from - import, która ładuje wszystko do głównej przestrzeni nazw? –

+2

Nie ma znaczenia, kiedy 'subtwo' działa (gdy główne' import' to), nic nie jest w * jego * przestrzeni nazw. –

+1

Warto pamiętać, że 'import' w Pythonie nie jest podobny do' include' w innych językach. –

3

Czy możesz wyjaśnić, dlaczego czujesz się jak subone powinny być dostępne dla subtwo, kiedy subone zostało zaimportowane przez main? W rzeczywistości subtwo.py można skompilować bez wiedzy o tym, co zaimportował main.py.

Ponadto, jeśli drugi program importuje subtwo.py, czy wiedza subwoi o subone zależy od tego, który z dwóch głównych programów importuje subtwo? Zmniejszyłoby to możliwość ponownego użycia subtwo.

Wygląda na to, że myślisz o kompilacji jako procesie o zdefiniowanej kolejności, gromadzeniu informacji o stanie: kompilacji main.py, podczas której kompilujemy/importujemy subone.py, gromadzimy z niej informacje, a następnie kompilujemy/import subtwo.py, korzystając z informacji, które już zgromadziliśmy.

Zamiast tego kompilacja każdego modułu jest niezależna od innych, chyba że deklarowane są zależności. To znacznie ułatwia ponowne użycie i konserwację kodu: istnieje mniej ukrytych zależności.

Czy dlatego, że to jest złe programowanie zostały importowanych modułów zależą od siebie inny, bez przechodzenia przez ich „macierzystego” modułu?

jako takie nie ... To jest po prostu złe programowanie mieć moduł 2 zależy od modułu 1 oczywistą, tak, to znaczy bez modułu 2 deklarując „I zależy od modułu 1”.

+1

Ach, rozumiem. Sposób, w jaki to opisujesz, pomaga. Myślę, że byłem przyzwyczajony do PHP 'include' i' require', które bezpośrednio kodują. Zamiast tego moduły są obiektami, które muszą zostać wywołane. –

+1

@willell: Nigdy nie używałem PHP, ale C jest podobne z preprocesorem '# include' właśnie wklejającym tam cały plik. Niezależnie od tego, jakaś niejawna zależność nie wydaje się mądra, niezależnie od języka. –

+0

@willell, to ma sens ... sposób, w jaki myślisz o tym, rzeczywiście pasuje do tego, jak działają mechanizmy PHP i C. Jednak możesz zobaczyć, jak to prowadzi do zależności, które są trudne do wykrycia ... Aby dowiedzieć się, od czego zależy plik B, musisz spojrzeć na wszystkie miejsca, w których znajduje się plik B. Istnieje więc zasadnicza różnica między "włączaniem pliku" a "importowaniem modułu". Ta pierwsza to raczej proste, dosłowne wstawianie ciągu tekstowego, nieświadome konsekwencji semantycznych. Ta ostatnia jest bardziej koncepcyjnym łączeniem jednego komponentu programu z drugim. – LarsH

0

Jeśli chodzi o drugi przykład, "main.py" wie o Nugget, ale "subtwo.py" nie.

Myślę, że to pomogłoby myśleć o tym w ten sposób. Każdy moduł (plik) musi działać tak, jakby jedynymi istniejącymi modułami były te, które importuje. W tym przypadku "subtwo.py" nie może być uruchamiany samodzielnie, ponieważ nie zaimportował Nugget. Zasadniczo "subtwo.py" nie wie, co wie "main.py". Nie powinien, ponieważ może być wywołany z dowolnego miejsca przez kogokolwiek, i nie może polegać na nikim innym, który importuje rzeczy, których potrzebuje.

0

Dzieje się tak, ponieważ importowane moduły mają oddzielne przestrzenie nazw.Co napisałeś jest bardzo podobny:

def func1(): 
    a = 1 

def func2(): 
    print a 

func1() 
func2() # This will throw an error 

a = 2 

func2() # Now this will print 2. 

Moduły mają swoje nazw lokalnie, a podczas korzystania from subone import * importowania nazw TYLKO main.py nazw, które nie mogą być dostępne przez subtwo.

Niemniej jednak - to, co próbujesz zrobić, to bardzo zła praktyka. Unikaj używania zmiennych globalnych i import *, tylko dlatego, że teraz będziesz coraz bardziej zdezorientowany.


Więcej o nim: https://docs.python.org/3/reference/import.html

https://bytebaker.com/2008/07/30/python-namespaces/

http://www.diveintopython.net/html_processing/locals_and_globals.html

a może: http://sebastianraschka.com/Articles/2014_python_scope_and_namespaces.html

Powiązane problemy