PEP 8 mówi:
- Importy są zawsze umieszczane na początku pliku, zaraz po komentarzach do modułów i dokumentach oraz przed wartościami globalnymi i stałymi modułu.
Czasami naruszam PEP 8. Czasami importuję rzeczy wewnątrz funkcji. Generalnie robię to, jeśli istnieje import, który jest używany tylko w ramach jednej funkcji.
Jakieś opinie?
EDYTUJ (powód, dla którego uważam, że importowanie w funkcjach może być dobrym pomysłem):
Główny powód: może uczynić kod bardziej przejrzystym.
- Patrząc na kod funkcji, mogę zadać sobie pytanie: „Co to jest funkcja / klasa xxx?” (xxx jest używany wewnątrz funkcji). Jeśli mam wszystkie moje importy na górze modułu, muszę tam zajrzeć, aby określić, co to jest xxx. Jest to bardziej problem podczas używania
from m import xxx
. Widzeniem.xxx
w funkcji pewnie mówi mi więcej. W zależności od tego, co tom
jest: Czy jest to dobrze znany moduł / pakiet (import m
) najwyższego poziomu ? Czy jest to podmoduł / pakiet (from a.b.c import m
)? - W niektórych przypadkach posiadanie tych dodatkowych informacji („Co to jest xxx?”) W pobliżu miejsca, w którym używane jest xxx, może ułatwić zrozumienie funkcji.
python
conventions
codeape
źródło
źródło
Odpowiedzi:
Myślę, że na dłuższą metę docenisz umieszczenie większości importowanych plików na początku pliku, dzięki czemu możesz od razu stwierdzić, jak skomplikowany jest Twój moduł, biorąc pod uwagę to, co musi zaimportować.
Jeśli dodaję nowy kod do istniejącego pliku, zwykle wykonuję import tam, gdzie jest to potrzebne, a jeśli kod pozostanie, sprawię, że wszystko będzie bardziej trwałe, przenosząc wiersz importu na początek pliku.
Jeszcze jedna kwestia, wolę uzyskać
ImportError
wyjątek przed uruchomieniem jakiegokolwiek kodu - jako sprawdzenie poprawności, więc to kolejny powód, aby importować u góry.Używam
pyChecker
do sprawdzenia nieużywanych modułów.źródło
Istnieją dwa przypadki, w których naruszam PEP 8 w tym zakresie:
import pdb; pdb.set_trace()
Jest to przydatne, b / c Nie chcę umieszczaćimport pdb
na górze każdego modułu, który chciałbym debugować, i łatwo zapamiętać, aby usunąć import, gdy usuwam punkt przerwania.Poza tymi dwoma przypadkami dobrze jest umieścić wszystko na górze. Sprawia, że zależności są wyraźniejsze.
źródło
Oto cztery przypadki użycia importu, których używamy
import
(ifrom x import y
iimport x as y
) u góryOpcje importu. Na górze.
Import warunkowy. Używany z bibliotekami JSON, XML i tym podobnymi. Na górze.
Dynamiczny import. Jak dotąd mamy tylko jeden przykład.
Zauważ, że ten dynamiczny import nie wprowadza kodu, ale wprowadza złożone struktury danych napisane w Pythonie. To trochę jak wytrawiony fragment danych, z wyjątkiem tego, że wytrawiliśmy go ręcznie.
Jest to również mniej więcej u góry modułu
Oto, co robimy, aby kod był bardziej przejrzysty:
Zadbaj o to, aby moduły były krótkie.
Jeśli mam wszystkie moje importy na górze modułu, muszę tam zajrzeć, aby ustalić, jaka jest nazwa. Jeśli moduł jest krótki, łatwo to zrobić.
W niektórych przypadkach posiadanie tych dodatkowych informacji blisko miejsca, w którym jest używana nazwa, może ułatwić zrozumienie funkcji. Jeśli moduł jest krótki, łatwo to zrobić.
źródło
Należy pamiętać o jednej rzeczy: niepotrzebny import może powodować problemy z wydajnością. Jeśli więc jest to funkcja, która będzie często wywoływana, lepiej po prostu umieścić import na górze. Oczywiście jest to optymalizacja, więc jeśli istnieje uzasadniony argument, że importowanie do funkcji jest bardziej przejrzyste niż importowanie na początku pliku, w większości przypadków jest to ważniejsze od wydajności.
Jeśli robisz IronPython, powiedziano mi, że lepiej jest importować funkcje wewnętrzne (ponieważ kompilacja kodu w IronPythonie może być powolna). W ten sposób możesz wtedy znaleźć sposób na importowanie funkcji wewnętrznych. Ale poza tym twierdzę, że po prostu nie warto walczyć z konwencjami.
Inną kwestią, którą chciałbym poruszyć, jest to, że może to być potencjalny problem z konserwacją. Co się stanie, jeśli dodasz funkcję korzystającą z modułu, który był wcześniej używany tylko przez jedną funkcję? Czy będziesz pamiętać o dodaniu importu na początku pliku? A może zamierzasz przeskanować każdą funkcję pod kątem importu?
FWIW, są przypadki, w których ma sens importowanie do funkcji. Na przykład, jeśli chcesz ustawić język w cx_Oracle, musisz ustawić
_
zmienną środowiskową NLS LANG przed jej zaimportowaniem. Dlatego możesz zobaczyć taki kod:źródło
Wcześniej złamałem tę zasadę dla modułów, które są autotestowane. Oznacza to, że są zwykle używane tylko do wsparcia, ale definiuję dla nich główne, więc jeśli uruchomisz je samodzielnie, możesz przetestować ich funkcjonalność. W takim przypadku czasami importuję
getopt
icmd
tylko w zasadzie, ponieważ chcę, aby ktoś czytający kod wiedział, że te moduły nie mają nic wspólnego z normalnym działaniem modułu i są uwzględniane tylko do testów.źródło
Wychodząc z pytania o dwukrotne załadowanie modułu - dlaczego nie oba?
Import w górnej części skryptu wskaże zależności, a kolejny import w funkcji sprawi, że ta funkcja będzie bardziej atomowa, ale pozornie nie spowoduje pogorszenia wydajności, ponieważ import ciągły jest tani.
źródło
O ile tak jest
import
i niefrom x import *
, należy je umieścić na górze. Dodaje tylko jedną nazwę do globalnej przestrzeni nazw, a ty trzymasz się PEP 8. Ponadto, jeśli później będziesz jej potrzebować gdzie indziej, nie musisz niczego przenosić.To nic wielkiego, ale ponieważ nie ma prawie żadnej różnicy, proponuję zrobić to, co mówi PEP 8.
źródło
from x import *
wewnątrz funkcji wygeneruje SyntaxWarning, przynajmniej w 2.5.Spójrz na alternatywne podejście, które jest używane w sqlalchemy: wstrzykiwanie zależności:
Zwróć uwagę, jak zaimportowana biblioteka jest zadeklarowana w dekoratorze i przekazana jako argument do funkcji !
Takie podejście sprawia, że kod jest czystszy, a także działa 4,5 razy szybciej niż
import
instrukcja!Benchmark: https://gist.github.com/kolypto/589e84fbcfb6312532658df2fabdb796
źródło
W modułach, które są zarówno „normalnymi” modułami i mogą być wykonywane (tj. Mają
if __name__ == '__main__':
sekcję), zwykle importuję moduły, które są używane tylko podczas wykonywania modułu w sekcji głównej.Przykład:
źródło
Jest jeszcze jeden przypadek (prawdopodobnie „narożnik”), w którym może być korzystne korzystanie z
import
rzadko używanych funkcji: skrócić czas uruchamiania.Kiedyś trafiłem w tę ścianę dość złożonym programem działającym na małym serwerze IoT, akceptującym polecenia z linii szeregowej i wykonującym operacje, być może bardzo złożone operacje.
Umieszczanie
import
instrukcji na górze plików, co ma na celu przetworzenie wszystkich importów przed uruchomieniem serwera; odimport
wykazu zawartegojinja2
,lxml
,signxml
i inne ciężary „ciężki” (SoC i nie był bardzo silny) oznaczało minut przed pierwszą instrukcją faktycznie wykonywane.OTOH umieszczając większość importów w funkcjach, w ciągu kilku sekund udało mi się „ożywić” serwer na linii szeregowej. Oczywiście, gdy moduły były faktycznie potrzebne, musiałem zapłacić cenę (uwaga: można to również złagodzić, uruchamiając zadanie w tle, które wykonuje je
import
w czasie bezczynności).źródło