Próbowałem znaleźć obszerny przewodnik na temat tego, czy najlepiej go używać, import module
czy 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 ?
python
python-import
Filip Dupanović
źródło
źródło
from … import …
pokrewny - Rozumowanie składni w Pythonie i „module importu” vs. ”z funkcji importu modułu”'from module import X,Y,Z
a'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 jestfrom module import *
z wieloma modułami.Odpowiedzi:
Różnica między
import module
ifrom module import foo
jest 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
import
wyciągów. Nie trzeba dodawać żadnych dodatkowych importów, aby rozpocząć korzystanie z innego elementu z modułumodule.foo
kodu może być żmudne i zbędne (nudę można zminimalizować, używającimport module as mo
następnie pisaniamo.foo
)from module import foo
foo
import
wyciągfoo
. 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,import
ale niezwykle trudno jest być pewnym.źródło
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.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:
moduł a:
moduł b:
Jednak jeśli zaimportujesz nazwy symboli zamiast nazw modułów, to nie zadziała.
Na przykład, jeśli zrobię to w module a:
Ż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”.
źródło
Mimo że wiele osób już wyjaśniało
import
vsimport 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.bar
Ale niebar
from foo import bar
:Importuje
foo
i tworzy odniesienia do wszystkich wymienionych członków (bar
). Nie ustawia zmiennejfoo
.Np.
bar
Ale niebaz
lubfoo.baz
from foo import *
:Importuje
foo
i 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
bar
abaz
jednak nie_qux
lubfoo._qux
.Zobaczmy, kiedy to zrobimy
import X.Y
:Sprawdź
sys.modules
z nazwąos
ios.path
:Sprawdź
globals()
ilocals()
przestrzeni nazw dicts zos
ios.path
:Z powyższego przykładu wynika, że tylko
os
lokalna i globalna przestrzeń nazw jest wstawiana. Powinniśmy więc móc użyć:Ale nie
path
.Raz na usunięciu
os
z nazw miejscowych (), nie będzie w stanie uzyskać dostępos
, a takżeos.path
, mimo że występują w sys.modules:Porozmawiajmy teraz o
import from
:from
:Sprawdź za
sys.modules
pomocąos
ios.path
: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()
aglobals()
przestrzeń nazw dyktuje:Możesz uzyskać dostęp, używając nazwy, a
path
nieos.path
:Usuńmy „ścieżkę” z
locals()
:Ostatni przykład użycia aliasu:
I nie zdefiniowano ścieżki:
źródło
as SYMBOL
w ogóle zmienia sposób działania tej odpowiedzi?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 module
Ogó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.źródło
from M import X
i 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.X
po tym imporcie.class m: from something.too.long import x, y, z
. Tak naprawdę nie poleciłbym tego.Ja osobiście zawsze używam
a następnie uzyskać dostęp do wszystkiego jako
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
w tym przypadku oczywiście napotykasz problemy, ale istnieje silna wskazówka, że układ twojego pakietu jest wadliwy i musisz go przemyśleć.
źródło
Najlepiej jest, gdy będziesz korzystać z wielu funkcji z modułu.
Jest najlepszy, gdy chcesz uniknąć zanieczyszczenia globalnej przestrzeni nazw wszystkimi funkcjami i typami z modułu, gdy tylko potrzebujesz
function
.źródło
Właśnie odkryłem jeszcze jedną subtelną różnicę między tymi dwiema metodami.
Jeśli moduł
foo
używa następującego importu:Następnie moduł
bar
może przez pomyłkę użyćcount
tak, jakby był zdefiniowany wfoo
, a nie witertools
:Jeśli
foo
używa:błąd jest nadal możliwy, ale rzadziej może zostać popełniony.
bar
musi: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.źródło
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
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
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.
źródło
Ponieważ jestem również początkującym, postaram się wyjaśnić to w prosty sposób: W Pythonie mamy trzy typy
import
instrukcji, które są:1. Import ogólny:
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:
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:
teraz zamiast używać
math.sqrt()
możesz użyćm.sqrt()
.2. Import funkcji:
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:
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
źródło
Z
import
token musi być modułem (plik zawierający polecenia Python) lub opakowanie (katalogu, wsys.path
zawierający plik__init__.py
).Gdy są podpakiety:
wymagania dla folderu (pakiet) lub pliku (moduł) są takie same, ale folder lub plik musi być w środku
package2
, który musi być w środkupackage1
, a zarównopackage1
ipackage2
musi zawierać__init__.py
pliki. https://docs.python.org/2/tutorial/modules.htmlW
from
stylu importu:pakiet lub moduł wpisuje przestrzeń nazw pliku zawierającego
import
instrukcję jakomodule
(lubpackage
) zamiastpackage1.package2.module
. Zawsze możesz powiązać z wygodniejszą nazwą:Tylko
from
styl importu pozwala nazwać określoną funkcję lub zmienną:jest dozwolone, ale
nie jest dozwolone.
źródło
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.źródło
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
...import
ponieważ 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ł.
źródło
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 variable
iprivate functions
z zaimportowanego modułu, co nie jest możliwe w przypadku instrukcji from-import .Kod na obrazku:
setting.py
plain_importer.py
from_importer.py
źródło
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.
źródło
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:
niż kiedy są powiązane z jakimś modułem:
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:
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.
źródło
Chciałbym dodać do tego, jest kilka rzeczy do rozważenia podczas wywołań importu:
Mam następującą strukturę:
main.py:
dis.dis pokazuje różnicę:
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
To działa
przyklad 2
Nie ma kości
przyklad 3
Podobny problem ... ale wyraźnie z x importu y nie jest tym samym, co import importu xy jak y
przyklad4
Ten też działa
źródło
Oto moja struktura katalogów mojego bieżącego katalogu:
import
Oświadczenie pamięta nazwy wszystkich pośrednich .Te nazwy muszą być kwalifikowane:
from ... import ...
Oświadczenie pamięta tylko nazwę importowanego .Ta nazwa nie może być kwalifikowana:
źródło
Jak wspomina Jan Wrobel , jednym z aspektów różnych importów jest sposób ich ujawnienia.
Moduł matematyki
Zastosowanie matematyki :
Jeśli zaimportowałem
gcd
tylko do użytku wewnętrznego, a nie w celu ujawnienia go użytkownikommymath
, 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 math
zamiast tego, zacząłem ukrywać import przed ujawnieniem, używając wiodącego podkreślenia: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.
źródło