Dlaczego moduły Pythona czasami nie importują swoich podmodułów?

88

Zauważyłem dzisiaj coś dziwnego, co chciałbym wyjaśnić. Nie byłem w 100% pewien, jak to sformułować jako pytanie, więc Google nie wchodzi w rachubę. Moduł logowania nie ma dostępu do modułu logging.handlers z jakiegoś dziwnego powodu. Spróbuj sam, jeśli mi nie wierzysz:

>>> import logging
>>> logging.handlers
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'handlers'
>>> import logging.handlers
>>> logging.handlers
<module 'logging.handlers' from '/usr/lib/python2.6/logging/handlers.pyc'>

Czy ktoś może wyjaśnić, dlaczego tak się dzieje?

chriscauley
źródło

Odpowiedzi:

119

W Pythonie moduły muszą zostać zaimportowane, zanim będą dostępne. import loggingimportuje tylko moduł logowania. Tak się składa, że loggingjest to pakiet z podmodułami, ale te podmoduły nadal nie są ładowane automatycznie. Musisz więc jawnie zaimportować, logging.handlerszanim uzyskasz do niego dostęp.

Jeśli zastanawiasz się, dlaczego czasami nie potrzebujesz tych dodatkowych importów: niektóre pakiety importują niektóre lub wszystkie podmoduły, gdy są importowane - po prostu wykonując te importy w swoich __init__.pyplikach. W innych przypadkach może to być coś innego, co importujesz, również importowane logging.handlers. Nie ma znaczenia, który fragment kodu jest importowany; tak długo, jak coś zostanie zaimportowane w procesie logging.handlersprzed uzyskaniem do niego dostępu, będzie tam. Czasami moduł, który wygląda jak pakiet, tak naprawdę nie jest jednym, jak osi os.path. osnie jest pakietem, po prostu importuje właściwy inny moduł (dla Twojej platformy) i wywołuje go path, abyś mógł uzyskać do niego dostęp jako os.path.

Thomas Wouters
źródło
4

Jestem również nowy w Pythonie i po wielu praktykach mogę teraz rozróżniać między pakietami (folderami), modułami (.py), klasami, zmiennymi ... itd.

jeśli chcesz, aby którykolwiek z folderów był pakietem pythona - musi zawierać __init__.pyplik, nawet pusty plik wystarczy !!!

i jak powiedział Thomas, możesz zaimportować dodatkowy moduł do __init__.py, jeśli chcesz !!! ale moduły / pakiety są dostępne dopiero po ich zaimportowaniu ...

jeśli chcesz zaimportować wszystko z modułu, którego możesz użyć

from logging import *

reszta możesz uzyskać dostęp do modułu obsługi, jak poniżej,

from logging import handlers
print dir(handlers)

shahjapan
źródło
5
Proszę nie używać from module import *. Prawie zawsze jest to błąd.
Thomas Wouters,
Jeśli chcesz, aby wszystko w pakiecie było importowane automatycznie, wykonaj te importy w init .py, zamiast ustawiać wszystko w init .py i robić gdzieś 'from package import *'.
Thomas Wouters,
2
@Pete: ponieważ „zanieczyszcza” standardową przestrzeń nazw, co prowadzi do niejasności i konfliktów. Gdybym to zrobił import zipperi zipper.open()wiedziałbyś dokładnie, do którego otwarcia dzwonię. W przeciwieństwie from zipper import *do tego open()jest to wbudowany otwarty lub zamek błyskawiczny. Otwarty lub coś innego. import zipper as zjest znacznie preferowane, jeśli znudzi ci się pisaniezipper
msw
3
@Pete: Jest to również problem, ponieważ możesz nieświadomie nadpisać część swojej przestrzeni nazw. Kiedyś używałem from, numpy import *ponieważ niektóre funkcje numpy nie działają, chyba że zaimportujesz wszystkie numpy (straszna wada projektowa z ich strony IMO), ale numpy ma OGROMNĄ liczbę obiektów, które importuje. Skończyło się na tym, że nadpisałem wiele funkcji (myślę, że kopia była jedną ... Jestem zbyt zmęczony, by to sprawdzić). Teraz importuję numpy jako np, jeśli mam zamiar używać numpy tak bardzo, że nie mogę znieść go w kółko.
chriscauley
2
@dustynachos, która funkcja numpy ma tę wadę?
Winston Ewert,
2

Thomas Wouters odpowiedział na to pytanie bardzo dobrze, ale niestety, znalazłem je dopiero po znalezieniu odpowiedzi w oryginalnej dokumentacji. Pomyślałem, że w tym celu dodam do tego, mając nadzieję, że w przyszłości pojawi się bliżej początku wyszukiwarki.

PYTANIE

Dlaczego pojawia się błąd: „ AttributeError: module„ module_name ”nie ma atrybutu„ sub_module_name ”, mimo że mój edytor (np. Visual Code) automatycznie uzupełnia nazwę podmodułu:

 import module_name
 module_name.sub_module_name(parameter)

ODPOWIEDŹ

Twój edytor opiera swoje autouzupełnianie na strukturze plików twojego projektu, a nie na zachowaniu Pythona. Podmoduły nie są importowane „automatycznie” podczas importowania modułu. Odniesienie Python Dokumentacja do informacji o tym, jak „automatycznie” podmodułów importu przy użyciu

 import module_name

Kluczowym wkładem w tę odpowiedź jest dodanie AttributeError podczas próby zaimportowania „modułu” lub „pakietu”

Mam nadzieję, że to komuś pomoże!

Niedomiar
źródło
1

Niedawno spotkałem się z tą samą dziwną sytuacją. Więc założę się, że usunąłeś import lib od strony trzeciej. Ta usunięta biblioteka zawierała from logging import handlerslub from logging import *udostępniła Ciebie handlers. A w innym scenariuszu miałeś coś podobnego import loggingi właśnie używałeś logging.handlersi pomyślałeś, że tak to działa, tak jak ja.

Alexey
źródło