Użyć „modułu importu” czy „z modułu importu”?

410

Próbowałem znaleźć obszerny przewodnik na temat tego, czy najlepiej go używać, import moduleczy from module import? Właśnie zacząłem od Pythona i staram się zacząć od najlepszych praktyk.

Zasadniczo miałem nadzieję, czy ktokolwiek może podzielić się swoimi doświadczeniami, jakie preferencje mają inni programiści i jaki jest najlepszy sposób na uniknięcie problemów ?

Filip Dupanović
źródło
5
Chciałem tylko poinformować, że wybrana odpowiedź jest błędna. Stwierdza, że ​​różnica jest subiektywna, podczas gdy istnieje różnica. Może to prowadzić do trudnych do wykrycia błędów. Zobacz odpowiedź Michaela Ray'a Lovettsa.
Mayou36
2
Jest ogromna różnica między importowaniem określonych nazwanych identyfikatorów 'from module import X,Y,Za'from module import * . Ten ostatni zanieczyszcza twoją przestrzeń nazw i może dawać nieprzewidywalne wyniki w zależności od tego, co dzieje się w module. Gorzej jest from module import *z wieloma modułami.
smci

Odpowiedzi:

474

Różnica między import modulei from module import foojest głównie subiektywna. Wybierz ten, który najbardziej ci się podoba i konsekwentnie z niego korzystaj. Oto kilka punktów, które pomogą Ci podjąć decyzję.

import module

  • Plusy:
    • Mniej konserwacji swoich importwyciągów. Nie trzeba dodawać żadnych dodatkowych importów, aby rozpocząć korzystanie z innego elementu z modułu
  • Cons:
    • Wpisywanie module.fookodu może być żmudne i zbędne (nudę można zminimalizować, używając import module as monastępnie pisania mo.foo)

from module import foo

  • Plusy:
    • Mniej pisania na klawiaturze foo
    • Większa kontrola nad tym, które elementy modułu są dostępne
  • Cons:
    • Aby użyć nowego elementu z modułu, musisz zaktualizować importwyciąg
    • Tracisz kontekst foo. Na przykład mniej jasne jest, co się ceil()dzieje w porównaniu z tymmath.ceil()

Każda z metod jest akceptowalna, ale nie należy jej używać from module import *.

W przypadku każdego rozsądnego dużego zestawu kodu, jeśli import *prawdopodobnie scementujesz go w module, nie będzie można go usunąć. Wynika to z faktu, że trudno jest określić, które elementy użyte w kodzie pochodzą z „modułu”, co ułatwia dotarcie do punktu, w którym myślisz, że już go nie używasz, importale niezwykle trudno jest być pewnym.

Mark Roddy
źródło
66
+1 za zniechęcanie do używania „z importu modułu *”, po prostu zaśmieca przestrzeń nazw.
Christian Witts,
22
zaśmiecanie przestrzeni nazw nie jest najbardziej problematyczną częścią „importu *”, jest to ograniczenie czytelności: wszelkie konflikty nazw pojawią się w testach (jednostkowych). Ale wszystkie nazwy, których użyjesz z importowanego modułu, będą puste, bez żadnej wskazówki, skąd pochodzą. Absolutnie nie znoszę „importować” ”.
Jürgen A. Erhard
21
Czy Zen Pythona nie mówi, że wyraźne jest lepsze niż dorozumiane?
Antony Koch
8
from module import *może być szczególnie użyteczny w przypadku stosowania go jako: if(windows):\n\t from module_win import * \n else: \n\t from module_lin import *. Wówczas moduł nadrzędny może potencjalnie zawierać nazwy funkcji niezależnych od systemu operacyjnego, jeśli nazwy funkcji w module_lin i module_win mają takie same nazwy. To jak warunkowo dziedziczenie obu klas.
anishsane
19
@anishsane. Jest inny sposób, aby to zrobić. zaimportuj moduł_win jako coś. Następnie zawsze używaj czegoś.
Nazwa_metody
163

Jest jeszcze jeden szczegół, nie wymieniony, związany z pisaniem do modułu. To prawda, że ​​może to nie być bardzo powszechne, ale od czasu do czasu potrzebowałem.

Ze względu na sposób, w jaki odwołania i powiązanie nazw działają w Pythonie, jeśli chcesz zaktualizować jakiś symbol w module, powiedzmy foo.bar, spoza tego modułu i mieć inny kod importujący „zobacz” tę zmianę, musisz zaimportować foo pewien sposób. Na przykład:

moduł foo:

bar = "apples"

moduł a:

import foo
foo.bar = "oranges"   # update bar inside foo module object

moduł b:

import foo           
print foo.bar        # if executed after a's "foo.bar" assignment, will print "oranges"

Jednak jeśli zaimportujesz nazwy symboli zamiast nazw modułów, to nie zadziała.

Na przykład, jeśli zrobię to w module a:

from foo import bar
bar = "oranges"

Żaden kod poza a nie będzie widział paska jako „pomarańcze”, ponieważ moje ustawienie paska tylko wpłynęło na nazwę „pasek” w module a, nie „sięgnęło” do obiektu modułu foo i nie zaktualizowało jego „paska”.

Michael Ray Lovett
źródło
Czy w tym ostatnim przykładzie nadal możesz wywołać „foo.bar =„ orange ””, aby zaktualizować „pasek” wewnątrz „foo”?
velocirabbit
4
Nie, w ostatnim przykładzie nazwa „foo” jest nieznana
Ghislain Leveque
31
Ta odpowiedź zapewnia „prawdziwą” odpowiedź na pytanie: jaka jest różnica między dwoma wariantami importu
Mayou36,
3
Napisałem fragment kodu, aby udowodnić, że ta odpowiedź jest absolutnie słuszna, ale jakie jest uzasadnienie tego?
huangbeidu
Myślę, że mówisz, że nazwy symboli importu mają zmienne lokalne, ale nazwy modułów importu mają zmienne globalne ???
WinEunuuchs2Unix,
79

Mimo że wiele osób już wyjaśniało importvs import from, chcę spróbować wyjaśnić nieco więcej, co dzieje się pod maską i gdzie są wszystkie miejsca, w których się zmienia.


import foo:

Import foo i tworzy odwołanie do tego modułu w bieżącej przestrzeni nazw. Następnie musisz zdefiniować ukończoną ścieżkę modułu, aby uzyskać dostęp do określonego atrybutu lub metody z wnętrza modułu.

Np. foo.barAle niebar

from foo import bar:

Importuje fooi tworzy odniesienia do wszystkich wymienionych członków ( bar). Nie ustawia zmiennejfoo .

Np. barAle nie bazlubfoo.baz

from foo import *:

Importuje fooi tworzy odwołania do wszystkich obiektów publicznych zdefiniowanych przez ten moduł w bieżącej przestrzeni nazw (wszystko wymienione w, __all__jeśli __all__istnieje, w przeciwnym razie wszystko, co nie zaczyna się _). Nie ustawia zmiennejfoo .

Np bara bazjednak nie _quxlub foo._qux.


Zobaczmy, kiedy to zrobimy import X.Y:

>>> import sys
>>> import os.path

Sprawdź sys.modulesz nazwą osi os.path:

>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>

Sprawdź globals()i locals()przestrzeni nazw dicts z osi os.path:

 >>> globals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> locals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> globals()['os.path']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'os.path'
>>>

Z powyższego przykładu wynika, że ​​tylko oslokalna i globalna przestrzeń nazw jest wstawiana. Powinniśmy więc móc użyć:

 >>> os
 <module 'os' from
  '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
 >>> os.path
 <module 'posixpath' from
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
 >>>

Ale nie path.

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

Raz na usunięciu osz nazw miejscowych (), nie będzie w stanie uzyskać dostęp os, a także os.path, mimo że występują w sys.modules:

>>> del locals()['os']
>>> os
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>> os.path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>

Porozmawiajmy teraz o import from:

from:

>>> import sys
>>> from os import path

Sprawdź za sys.modulespomocą osi os.path:

>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>

Zauważyliśmy, sys.modulesże znaleźliśmy to samo, co poprzednio, używającimport name

OK, sprawdźmy, jak to wygląda w, locals()a globals()przestrzeń nazw dyktuje:

>>> globals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> locals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['os']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'os'
>>>

Możesz uzyskać dostęp, używając nazwy, a pathnie os.path:

>>> path
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> os.path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>

Usuńmy „ścieżkę” z locals():

>>> del locals()['path']
>>> path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>

Ostatni przykład użycia aliasu:

>>> from os import path as HELL_BOY
>>> locals()['HELL_BOY']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['HELL_BOY']
<module 'posixpath' from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>>

I nie zdefiniowano ścieżki:

>>> globals()['path']
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
KeyError: 'path'
>>>
James Sapam
źródło
8
Chociaż jest to pełne, to naprawdę najlepsza odpowiedź na liście na dość złożone pytanie. Zawiera rzeczywisty kod, który pomaga wyjaśnić subtelności „pod maską”, które są ważniejsze niż styl, w tym konkretnym problemie. Chciałbym móc głosować więcej niż jeden raz!
Mike Williamson,
Czy używanie as SYMBOLw ogóle zmienia sposób działania tej odpowiedzi?
Maximilian Burszley
40

Oba sposoby są obsługiwane z jednego powodu: są chwile, kiedy jeden jest bardziej odpowiedni od drugiego.

  • import module: miło, gdy używasz wielu bitów z modułu. Wadą jest konieczność zakwalifikowania każdego odwołania do nazwy modułu.

  • from module import ...: fajnie, że importowane elementy są użyteczne bezpośrednio bez prefiksu nazwy modułu. Wadą jest to, że musisz wymienić każdą rzecz, której używasz, i że w kodzie nie jest jasne, skąd coś pochodzi.

To, którego użyć, zależy od tego, co czyni kod jasnym i czytelnym, i ma więcej niż trochę wspólnego z osobistymi preferencjami. import moduleOgólnie pochylam się, ponieważ w kodzie jest bardzo jasne, skąd pochodzi obiekt lub funkcja. Używam, from module import ...gdy często używam jakiegoś obiektu / funkcji w kodzie.

dwc
źródło
1
Czy istnieje sposób na wykorzystanie from M import Xi nadal czerpanie korzyści z korzystania z kwalifikatorów? Wydaje się, że możesz uzyskać to, co najlepsze z obu światów, jeśli nadal możesz to zrobić M.Xpo tym imporcie.
stawonogi
@artgropod: Kinda. Można to zrobić class m: from something.too.long import x, y, z. Tak naprawdę nie poleciłbym tego.
Lie Ryan,
35

Ja osobiście zawsze używam

from package.subpackage.subsubpackage import module

a następnie uzyskać dostęp do wszystkiego jako

module.function
module.modulevar

itd. Powodem jest to, że w tym samym czasie masz krótkie wywołanie i wyraźnie definiujesz przestrzeń nazw modułów dla każdej procedury, co jest bardzo przydatne, jeśli musisz szukać użycia danego modułu w źródle.

Nie trzeba dodawać, że nie używaj importu *, ponieważ zanieczyszcza on twoją przestrzeń nazw i nie mówi, skąd pochodzi dana funkcja (z którego modułu)

Oczywiście możesz mieć kłopoty, jeśli masz tę samą nazwę modułu dla dwóch różnych modułów w dwóch różnych pakietach, takich jak

from package1.subpackage import module
from package2.subpackage import module

w tym przypadku oczywiście napotykasz problemy, ale istnieje silna wskazówka, że ​​układ twojego pakietu jest wadliwy i musisz go przemyśleć.

Stefano Borini
źródło
10
W ostatnim przypadku zawsze możesz użyć: zaimportuj pkgN.sub.module jako modN, podając różne nazwy dla każdego modułu. Możesz także użyć wzorca „import modulename as mod1”, aby skrócić długą nazwę lub przełączać między implementacjami tego samego API (np. Modułów DB API) z jedną zmianą nazwy.
Jeff Shannon
15
import module

Najlepiej jest, gdy będziesz korzystać z wielu funkcji z modułu.

from module import function

Jest najlepszy, gdy chcesz uniknąć zanieczyszczenia globalnej przestrzeni nazw wszystkimi funkcjami i typami z modułu, gdy tylko potrzebujesz function.

Andrew Hare
źródło
7
Z pewnością jedyną rzeczą w globalnej przestrzeni nazw, jeśli wykonasz „moduł importu”, jest „moduł”? Zanieczyszczasz przestrzeń nazw tylko wtedy, gdy wykonasz polecenie „z .. import *”.
John Fouhy,
10

Właśnie odkryłem jeszcze jedną subtelną różnicę między tymi dwiema metodami.

Jeśli moduł fooużywa następującego importu:

from itertools import count

Następnie moduł barmoże przez pomyłkę użyć counttak, jakby był zdefiniowany w foo, a nie w itertools:

import foo
foo.count()

Jeśli fooużywa:

import itertools

błąd jest nadal możliwy, ale rzadziej może zostać popełniony. barmusi:

import foo
foo.itertools.count()

To spowodowało pewne problemy. Miałem moduł, który przez pomyłkę zaimportował wyjątek z modułu, który go nie zdefiniował, tylko zaimportował go z innego modułu (za pomocą from module import SomeException). Kiedy import nie był już potrzebny i usunięty, moduł naruszający został zepsuty.

Jan Wróbel
źródło
10

Oto kolejna różnica, o której nie wspomniano. Jest to kopiowane dosłownie z http://docs.python.org/2/tutorial/modules.html

Pamiętaj, że podczas korzystania

from package import item

element może być podmodułem (lub podpakietem) pakietu lub inną nazwą zdefiniowaną w pakiecie, taką jak funkcja, klasa lub zmienna. Instrukcja import najpierw sprawdza, czy element jest zdefiniowany w paczce; jeśli nie, zakłada, że ​​jest to moduł i próbuje go załadować. Jeśli nie uda się go znaleźć, zgłaszany jest wyjątek ImportError.

Przeciwnie, gdy używa się podobnej składni

import item.subitem.subsubitem

każda pozycja oprócz ostatniej musi być paczką; ostatni element może być modułem lub pakietem, ale nie może być klasą, funkcją lub zmienną zdefiniowaną w poprzednim elemencie.

użytkownik2141737
źródło
Inną rzeczą, którą zauważyłem, jest to, że jeśli element jest również submodułem w pakiecie, wtedy „z pakietu import elementu” działa, ale „import pakietu” package.item.subitem = ... nie działa z pustym init .py pakietu, chyba że mieć „element importu” w pliku inicjującym pakietu.
Amitoz Dandiana,
6

Ponieważ jestem również początkującym, postaram się wyjaśnić to w prosty sposób: W Pythonie mamy trzy typy importinstrukcji, które są:

1. Import ogólny:

import math

ten rodzaj importu jest moim ulubionym, jedynym minusem tej techniki importu jest to, że jeśli potrzebujesz użyć dowolnej funkcji modułu, musisz użyć następującej składni:

math.sqrt(4)

oczywiście zwiększa wysiłek pisania, ale jako początkujący pomoże ci śledzić moduł i funkcje z nim związane (dobry edytor tekstu znacznie zmniejszy wysiłek pisania i jest zalecany).

Wysiłek związany z pisaniem można jeszcze bardziej ograniczyć za pomocą tej instrukcji importu:

import math as m

teraz zamiast używać math.sqrt()możesz użyć m.sqrt().

2. Import funkcji:

from math import sqrt

ten typ importu najlepiej nadaje się, jeśli kod wymaga tylko dostępu do jednej lub kilku funkcji z modułu, ale aby użyć dowolnego nowego elementu z modułu, musisz zaktualizować instrukcję importu.

3. Uniwersalny przywóz:

from math import * 

Chociaż znacznie zmniejsza nakłady na pisanie, ale nie jest zalecane, ponieważ wypełni Twój kod różnymi funkcjami z modułu, a ich nazwa może kolidować z nazwą funkcji zdefiniowanych przez użytkownika. przykład:

Jeśli masz własną funkcję sqrt i importujesz matematykę, twoja funkcja jest bezpieczna: jest twoja sqrt i jest matematyka.sqrt. Jednak w przypadku importu matematycznego * masz problem: mianowicie dwie różne funkcje o dokładnie takiej samej nazwie. Źródło: Codecademy

Shashank Rawat
źródło
5
import package
import module

Z importtoken musi być modułem (plik zawierający polecenia Python) lub opakowanie (katalogu, w sys.pathzawierający plik __init__.py).

Gdy są podpakiety:

import package1.package2.package
import package1.package2.module

wymagania dla folderu (pakiet) lub pliku (moduł) są takie same, ale folder lub plik musi być w środku package2, który musi być w środku package1, a zarówno package1i package2musi zawierać __init__.pypliki. https://docs.python.org/2/tutorial/modules.html

W fromstylu importu:

from package1.package2 import package
from package1.package2 import module

pakiet lub moduł wpisuje przestrzeń nazw pliku zawierającego importinstrukcję jako module(lub package) zamiast package1.package2.module. Zawsze możesz powiązać z wygodniejszą nazwą:

a = big_package_name.subpackage.even_longer_subpackage_name.function

Tylko fromstyl importu pozwala nazwać określoną funkcję lub zmienną:

from package3.module import some_function

jest dozwolone, ale

import package3.module.some_function 

nie jest dozwolone.

Bennett Brown
źródło
4

Dodając do tego, co ludzie powiedzieli from x import *: oprócz tego, że trudniej jest stwierdzić, skąd pochodzą nazwy, wyrzuca to programy sprawdzające kod, takie jak Pylint. Będą zgłaszać te nazwy jako niezdefiniowane zmienne.

DNS
źródło
3

Moja odpowiedź na to pytanie zależy głównie od tego, ile różnych modułów będę używać. Jeśli zamierzam użyć tylko jednego lub dwóch, często używam from... importponieważ powoduje to mniejszą liczbę naciśnięć klawiszy w pozostałej części pliku, ale jeśli zamierzam użyć wielu różnych modułów, wolę tylkoimport ponieważ oznacza to, że każde odwołanie do modułu jest samok dokumentujące. Widzę, skąd pochodzi każdy symbol, bez konieczności polowania.

Zwykle wolę samokontryczny styl zwykłego importu i zmieniam na import z ... tylko wtedy, gdy muszę wpisać nazwę modułu, wzrasta od 10 do 20, nawet jeśli importowany jest tylko jeden moduł.

SingleNegationElimination
źródło
1

Jedną ze znaczących różnic, o których dowiedziałem się, o której zaskakująco nikt nie mówił, jest to, że za pomocą zwykłego importu można uzyskać dostęp private variablei private functionsz zaimportowanego modułu, co nie jest możliwe w przypadku instrukcji from-import .

wprowadź opis zdjęcia tutaj

Kod na obrazku:

setting.py

public_variable = 42
_private_variable = 141
def public_function():
    print("I'm a public function! yay!")
def _private_function():
    print("Ain't nobody accessing me from another module...usually")

plain_importer.py

import settings
print (settings._private_variable)
print (settings.public_variable)
settings.public_function()
settings._private_function()

# Prints:
# 141
# 42
# I'm a public function! yay!
# Ain't nobody accessing me from another module...usually

from_importer.py

from settings import *
#print (_private_variable) #doesn't work
print (public_variable)
public_function()
#_private_function()   #doesn't work
Saurav Sahu
źródło
0

Importuj moduł - nie potrzebujesz dodatkowych wysiłków, aby pobrać inną rzecz z modułu. Ma wady, takie jak redundantne pisanie

Moduł Importuj z - Mniej pisania i większa kontrola nad tym, które elementy modułu są dostępne. Aby użyć nowego elementu z modułu, musisz zaktualizować instrukcję importu.

Dlucidone
źródło
0

Istnieje kilka wbudowanych modułów, które zawierają głównie nagie funkcje ( base64 , matematyka , os , shutil , sys , time , ...) i zdecydowanie dobrą praktyką jest powiązanie tych nagich funkcji z pewną przestrzenią nazw, a tym samym poprawienie czytelności twojego kod. Zastanów się, jak trudniej jest zrozumieć znaczenie tych funkcji bez ich przestrzeni nazw:

copysign(foo, bar)
monotonic()
copystat(foo, bar)

niż kiedy są powiązane z jakimś modułem:

math.copysign(foo, bar)
time.monotonic()
shutil.copystat(foo, bar)

Czasami potrzebujesz nawet przestrzeni nazw, aby uniknąć konfliktów między różnymi modułami ( json.load vs. pickle.load )


Z drugiej strony istnieje kilka modułów, które zawierają głównie klasy ( configparser , datetime , tempfile , zipfile , ...) i wiele z nich sprawia, że ​​ich nazwy klas są wystarczająco zrozumiałe:

configparser.RawConfigParser()
datetime.DateTime()
email.message.EmailMessage()
tempfile.NamedTemporaryFile()
zipfile.ZipFile()

więc może być debata, czy użycie tych klas z dodatkową przestrzenią nazw modułów w kodzie dodaje trochę nowych informacji, czy tylko wydłuża kod.

Jeyekomon
źródło
0

Chciałbym dodać do tego, jest kilka rzeczy do rozważenia podczas wywołań importu:

Mam następującą strukturę:

mod/
    __init__.py
    main.py
    a.py
    b.py
    c.py
    d.py

main.py:

import mod.a
import mod.b as b
from mod import c
import d

dis.dis pokazuje różnicę:

  1           0 LOAD_CONST               0 (-1)
              3 LOAD_CONST               1 (None)
              6 IMPORT_NAME              0 (mod.a)
              9 STORE_NAME               1 (mod)

  2          12 LOAD_CONST               0 (-1)
             15 LOAD_CONST               1 (None)
             18 IMPORT_NAME              2 (b)
             21 STORE_NAME               2 (b)

  3          24 LOAD_CONST               0 (-1)
             27 LOAD_CONST               2 (('c',))
             30 IMPORT_NAME              1 (mod)
             33 IMPORT_FROM              3 (c)
             36 STORE_NAME               3 (c)
             39 POP_TOP

  4          40 LOAD_CONST               0 (-1)
             43 LOAD_CONST               1 (None)
             46 IMPORT_NAME              4 (mod.d)
             49 LOAD_ATTR                5 (d)
             52 STORE_NAME               5 (d)
             55 LOAD_CONST               1 (None)

W końcu wyglądają tak samo (STORE_NAME jest wynikiem w każdym przykładzie), ale warto to zauważyć, jeśli musisz rozważyć następujące cztery okrągłe importy:

Przykład 1

foo/
   __init__.py
   a.py
   b.py
a.py:
import foo.b 
b.py:
import foo.a
>>> import foo.a
>>>

To działa

przyklad 2

bar/
   __init__.py
   a.py
   b.py
a.py:
import bar.b as b
b.py:
import bar.a as a
>>> import bar.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "bar\a.py", line 1, in <module>
    import bar.b as b
  File "bar\b.py", line 1, in <module>
    import bar.a as a
AttributeError: 'module' object has no attribute 'a'

Nie ma kości

przyklad 3

baz/
   __init__.py
   a.py
   b.py
a.py:
from baz import b
b.py:
from baz import a
>>> import baz.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "baz\a.py", line 1, in <module>
    from baz import b
  File "baz\b.py", line 1, in <module>
    from baz import a
ImportError: cannot import name a

Podobny problem ... ale wyraźnie z x importu y nie jest tym samym, co import importu xy jak y

przyklad4

qux/
   __init__.py
   a.py
   b.py
a.py:
import b 
b.py:
import a
>>> import qux.a
>>>

Ten też działa

ahfx
źródło
0

Oto moja struktura katalogów mojego bieżącego katalogu:

.  
└─a  
   └─b  
     └─c
  1. importOświadczenie pamięta nazwy wszystkich pośrednich .
    Te nazwy muszą być kwalifikowane:

    In[1]: import a.b.c
    
    In[2]: a
    Out[2]: <module 'a' (namespace)>
    
    In[3]: a.b
    Out[3]: <module 'a.b' (namespace)>
    
    In[4]: a.b.c
    Out[4]: <module 'a.b.c' (namespace)>
  2. from ... import ...Oświadczenie pamięta tylko nazwę importowanego .
    Ta nazwa nie może być kwalifikowana:

    In[1]: from a.b import c
    
    In[2]: a
    NameError: name 'a' is not defined
    
    In[2]: a.b
    NameError: name 'a' is not defined
    
    In[3]: a.b.c
    NameError: name 'a' is not defined
    
    In[4]: c
    Out[4]: <module 'a.b.c' (namespace)>

  • Uwaga: Oczywiście zrestartowałem konsolę Python między krokami 1 i 2.
MarianD
źródło
0

Jak wspomina Jan Wrobel , jednym z aspektów różnych importów jest sposób ich ujawnienia.

Moduł matematyki

from math import gcd
...

Zastosowanie matematyki :

import mymath
mymath.gcd(30, 42)  # will work though maybe not expected

Jeśli zaimportowałem gcdtylko do użytku wewnętrznego, a nie w celu ujawnienia go użytkownikom mymath, może to być niewygodne. Mam to dość często iw większości przypadków chcę „utrzymywać moduły w czystości”.

Oprócz propozycji Jana Wrobla, aby to trochę zaciemnić, używając import mathzamiast tego, zacząłem ukrywać import przed ujawnieniem, używając wiodącego podkreślenia:

# for instance...
from math import gcd as _gcd
# or...
import math as _math

W większych projektach ta „najlepsza praktyka” pozwala mi dokładnie kontrolować, co jest ujawniane przy późniejszym imporcie, a co nie. Utrzymuje to moje moduły w czystości i spłaca określony projekt.

Matheburg
źródło