Co jest złego w relatywnym imporcie w Pythonie?

89

Niedawno zaktualizowałem wersje pylint , popularnego narzędzia sprawdzającego styl Python.

W całym moim kodzie stało się to balistyczne, wskazując miejsca, w których importuję moduły w tym samym pakiecie, bez określania pełnej ścieżki pakietu.

Nowy komunikat o błędzie to W0403.

W0403: Względny import% r powinien wynosić% r

Używane, gdy wykryty zostanie import w stosunku do katalogu pakietu.


Przykład

Na przykład, jeśli moje pakiety mają następującą strukturę:

/cake
  /__init__.py
  /icing.py
  /sponge.py
/drink

a w pakiecie gąbek piszę:

import icing

zamiast

import cake.icing

Otrzymam ten błąd.


Chociaż rozumiem, że nie wszystkie wiadomości Pylint mają takie samo znaczenie i nie boję się ich odrzucić, nie rozumiem, dlaczego taka praktyka jest uważana za zły pomysł.

Miałem nadzieję, że ktoś może wyjaśnić pułapki, więc mógłbym poprawić swój styl kodowania zamiast (jak obecnie planuję) wyłączyć to pozornie fałszywe ostrzeżenie.

Dziwne
źródło

Odpowiedzi:

97

Problem import icingpolega na tym, że nie wiesz, czy jest to import absolutny, czy import względny. icingmoże moduł w ścieżce Pythona lub pakiet w bieżącym module. Jest to dość denerwujące, gdy pakiet lokalny ma taką samą nazwę jak standardowy pakiet biblioteki Pythona.

Możesz zrobić to, from __future__ import absolute_importco całkowicie wyłącza niejawny import względny. Zostało to opisane, łącznie z tym uzasadnieniem niejednoznaczności, w PEP 328 . Uważam, że Python 3000 całkowicie ukrył import niejawny.

Nadal możesz wykonywać import względny, ale musisz to zrobić jawnie, w następujący sposób:

from . import icing
Winston Ewert
źródło
2
+1, szczególnie za rozwiązanie kompromisowe, które prawdopodobnie jest tym, co powinienem iść.
Dziwne,
2
Pamiętaj, że możesz to zrobić import .icingzamiastfrom . import icing
Jack
11
@ Jack właściwie nie sądzę, żebyś mógł. Z tej części PEP328 : import względny musi zawsze używać from <> import; import <>jest zawsze absolutne. Oczywiście import bezwzględny można wykorzystać from <> import, pomijając wiodące kropki. Powód import .foojest zabroniony, ponieważ po tym import XXX.YYY.ZZZczasie XXX.YYY.ZZZmożna go użyć w wyrażeniu. Ale .moduleYnie nadaje się do użycia w wyrażeniu.
A.Wan
48

Istnieje kilka dobrych powodów:

  1. Import względny łatwo się psuje, gdy przenosisz moduł.

    Wyobraź sobie, że masz foo.bar, A foo.bazi bazmoduł w swoim pakiecie. foo.barimportuje foo.baz, ale używając importu względnego.

    Teraz, jeśli były, aby przejść foo.bardo bar, twój moduł nagle importuje inny baz!

  2. Względny import jest niejednoznaczny. Nawet bez poruszania się po barmodule w powyższym przykładzie nowy deweloper przychodzący do twojego projektu może zostać wybaczony za to, że nie zdaje sobie sprawy, że baztak naprawdę jest foo.bazzamiast pakietu głównego baz.

    Bezwzględny import wyraźnie wskazuje, który moduł jest używany. I jak import thisgłosi kazanie, wyraźne jest lepsze niż dorozumiane.

  3. Python 3 całkowicie wyłączył import niejawny; importy są teraz zawsze interpretowane jako absolutne, co oznacza, że ​​w powyższym przykładzie import bazzawsze będzie importował moduł najwyższego poziomu. Zamiast tego będziesz musiał użyć jawnej składni importu ( from . import baz).

    Przeniesienie przykładu z Pythona 2 do 3 doprowadziłoby zatem do nieoczekiwanych problemów, użycie importu absolutnego sprawi, że Twój kod będzie przyszłościowy.

Martijn Pieters
źródło
10
+1 za # 2 i # 3. Ale numer 1 musi zostać zrównoważony z tym, co dzieje się, gdy cały katalog jest przenoszony (np. Zepchnięty o poziom).
Dziwne,