Adakah yang bisa menjelaskan impor relatif python?

174

Saya tidak bisa seumur hidup saya mendapatkan impor relatif python untuk bekerja. Saya telah membuat contoh sederhana di mana itu tidak berfungsi:

Struktur direktori adalah:

/__init__.py
/start.py
/parent.py
/sub/__init__.py
/sub/relative.py

/start.py hanya mengandung: import sub.relative

/sub/relative.py hanya mengandung from .. import parent

Semua file lainnya kosong.

Saat menjalankan yang berikut di baris perintah:

$ cd /
$ python start.py

Saya mendapat:

Traceback (most recent call last):
  File "start.py", line 1, in <module>
    import sub.relative
  File "/home/cvondrick/sandbox/sub/relative.py", line 1, in <module>
    from .. import parent
ValueError: Attempted relative import beyond toplevel package

Saya menggunakan Python 2.6. Mengapa demikian? Bagaimana cara membuat contoh kotak pasir ini berfungsi?

carl
sumber

Jawaban:

140

Anda mengimpor dari paket "sub". start.pytidak dengan sendirinya dalam sebuah paket bahkan jika ada __init__.pyhadiah.

Anda perlu memulai program Anda dari satu direktori di atas parent.py:

./start.py

./pkg/__init__.py
./pkg/parent.py
./pkg/sub/__init__.py
./pkg/sub/relative.py

Dengan start.py:

import pkg.sub.relative

Sekarang pkg adalah paket tingkat atas dan impor relatif Anda akan berfungsi.


Jika Anda ingin tetap dengan tata letak Anda saat ini, Anda bisa menggunakan import parent. Karena Anda gunakan start.pyuntuk meluncurkan juru bahasa Anda, direktori di mana start.pyberada di jalur python Anda. parent.pytinggal di sana sebagai modul terpisah.

Anda juga dapat menghapus level atas dengan aman __init__.py, jika Anda tidak mengimpor apa pun ke dalam skrip lebih jauh ke pohon direktori.

ebo
sumber
2
Anda membingungkan istilah 'modul' dan 'paket'. 'start.py' mewakili modul 'start', 'mod' dan 'mod.sub' adalah paket, 'mod' adalah paket tingkat atas.
Ferdinand Beyer
34
Terima kasih, tetapi ini sejujurnya sepertinya konyol. Untuk bahasa yang begitu indah, saya tidak percaya para desainer akan membuat batasan seperti itu. Apakah tidak ada cara lain?
carl
2
Sama sekali tidak konyol. Impor relatif adalah rujukan untuk merujuk ke modul saudara dalam suatu paket. Jika Anda ingin mengimpor modul tingkat atas, gunakan impor absolut.
Ferdinand Beyer
58
Tidak konyol Jadi dalam bash, tidak dapat menangani relatif relatif atas dengan ".." tidak akan mengganggu Anda?
e-satis
2
Menurut saya ide python adalah menggunakan impor "absolut" dari direktori tempat Anda meluncurkan skrip induk Anda. Jadi Anda dapat menggunakan path absolut "import parent" untuk mengimpor modul parent dari saudara. Dan relatif mengimpor semacam warisan atau apa pun ..
Odysseus
35

Jika Anda akan menelepon relative.pylangsung dan jika Anda benar-benar ingin mengimpor dari modul tingkat atas, Anda harus menambahkannya secara eksplisit ke sys.pathdaftar.
Inilah cara kerjanya:

# Add this line to the beginning of relative.py file
import sys
sys.path.append('..')

# Now you can do imports from one directory top cause it is in the sys.path
import parent

# And even like this:
from parent import Parent

Jika menurut Anda hal di atas dapat menyebabkan semacam ketidakkonsistenan, Anda dapat menggunakan ini sebagai gantinya:

sys.path.append(sys.path[0] + "/..")

sys.path[0] merujuk ke jalur tempat titik masuk itu berlari.

AmirHossein
sumber
3

Mengeceknya di python3:

python -V
Python 3.6.5

Contoh 1:

.
├── parent.py
├── start.py
└── sub
    └── relative.py

- start.py
import sub.relative

- parent.py
print('Hello from parent.py')

- sub/relative.py
from .. import parent

Jika kita menjalankannya seperti ini (hanya untuk memastikan PYTHONPATH kosong):

PYTHONPATH='' python3 start.py

Keluaran:

Traceback (most recent call last):
  File "start.py", line 1, in <module>
    import sub.relative
  File "/python-import-examples/so-example-v1/sub/relative.py", line 1, in <module>
    from .. import parent
ValueError: attempted relative import beyond top-level package

Jika kami mengubah impor sub/relative.py

- sub/relative.py
import parent

Jika kita jalankan seperti ini:

PYTHONPATH='' python3 start.py

Keluaran:

Hello from parent.py

Contoh2:

.
├── parent.py
└── sub
    ├── relative.py
    └── start.py

- parent.py
print('Hello from parent.py')

- sub/relative.py
print('Hello from relative.py')

- sub/start.py
import relative
from .. import parent

Jalankan seperti:

PYTHONPATH='' python3 sub/start.py

Keluaran:

Hello from relative.py
Traceback (most recent call last):
  File "sub/start.py", line 2, in <module>
    from .. import parent
ValueError: attempted relative import beyond top-level package

Jika kami mengubah impor di sub/start.py:

- sub/start.py
import relative
import parent

Jalankan seperti:

PYTHONPATH='' python3 sub/start.py

Keluaran:

Hello from relative.py
Traceback (most recent call last):
  File "sub/start.py", line 3, in <module>
    import parent
ModuleNotFoundError: No module named 'parent'

Jalankan seperti:

PYTHONPATH='.' python3 sub/start.py

Keluaran:

Hello from relative.py
Hello from parent.py

Juga lebih baik menggunakan impor dari folder root, yaitu:

- sub/start.py
import sub.relative
import parent

Jalankan seperti:

PYTHONPATH='.' python3 sub/start.py

Keluaran:

Hello from relative.py
Hello from parent.py
mrgloom
sumber