Saya mencoba mengikuti PEP 328 , dengan struktur direktori berikut:
pkg/
__init__.py
components/
core.py
__init__.py
tests/
core_test.py
__init__.py
Dalam core_test.py
Saya memiliki pernyataan impor berikut
from ..components.core import GameLoopEvents
Namun, ketika saya menjalankan, saya mendapatkan kesalahan berikut:
tests$ python core_test.py
Traceback (most recent call last):
File "core_test.py", line 3, in <module>
from ..components.core import GameLoopEvents
ValueError: Attempted relative import in non-package
Mencari di sekitar saya menemukan " jalur relatif tidak bekerja bahkan dengan __init__.py " dan " Impor modul dari jalur relatif " tetapi mereka tidak membantu.
Apakah ada sesuatu yang saya lewatkan di sini?
python
package
python-import
importerror
init
skytreader
sumber
sumber
unittest
proyek, jadi saya menulis proyek sampel yang cukup lengkap ini yang mencakup bersarang modul yang mendalam, impor relatif dan absolut (di mana pekerjaan dan tidak), dan referensi relatif dan absolut dari dalam paket, serta impor kelas tingkat tunggal, ganda, dan paket. Membantu hal-hal yang jelas sampai untuk saya!no module named myimports.foo
saat saya menjalankannya.cd
kePyImports
, dan menjalankanpython -m unittest tests.test_abs
, misalnya.Jawaban:
Iya. Anda tidak menggunakannya sebagai paket.
sumber
__init__.py
semua jalan turun, dan__package__
tipuan -modifying (dijelaskan di bawah oleh BrenBarn) diperlukan untuk memungkinkan impor ini untuk skrip yang dapat dieksekusi (misalnya ketika menggunakan shebang dan lakukan./my_script.py
di shell Unix) semuanya akan berguna. Seluruh masalah ini cukup sulit bagi saya untuk mencari tahu atau menemukan dokumentasi yang ringkas dan dapat dipahami.pkg
pada titik di mana Anda memanggil saluran ini dari CLI. Maka, itu harus bekerja seperti yang diharapkan. Jika Anda di dalampkg
dan meneleponpython -m tests.core_test
, itu tidak akan berhasil. Setidaknya itu bukan untuk saya.__init__.py
file namun Anda tetap mendapatkanValueError: Attempted relative import in non-package
kesalahan. Saya akan membayar uang yang sangat baik untuk seseorang, di suatu tempat, untuk akhirnya menjelaskan dalam bahasa Inggris yang sederhana bagaimana semua ini bekerja.Untuk menguraikan jawaban Ignacio Vazquez-Abrams :
Mekanisme impor Python bekerja relatif terhadap
__name__
file saat ini. Ketika Anda mengeksekusi file secara langsung, itu tidak memiliki nama yang biasa, tetapi memiliki"__main__"
sebagai namanya. Jadi impor relatif tidak berfungsi.Anda dapat, seperti yang disarankan Igancio, jalankan menggunakan
-m
opsi. Jika Anda memiliki bagian dari paket Anda yang dimaksudkan untuk dijalankan sebagai skrip, Anda juga dapat menggunakan__package__
atribut untuk memberi tahu file itu nama apa yang seharusnya ada dalam hierarki paket.Lihat http://www.python.org/dev/peps/pep-0366/ untuk detailnya.
sumber
python -m core_test
dari dalamtests
subdirektori - itu harus dari orangtua, atau Anda harus menambahkan induk ke jalan.__package__
untuk memastikan file skrip yang dapat dieksekusi relatif dapat mengimpor modul lain dari dalam paket yang sama. Tidak ada cara untuk mengimpor dari "keseluruhan sistem" secara relatif. Saya bahkan tidak yakin mengapa Anda ingin melakukan ini.__package__
simbol diatur ke "parent.child" maka Anda akan dapat mengimpor "parent.other_child". Mungkin saya tidak mengucapkannya dengan baik.script.py
dalam paketpack.subpack
, maka pengaturan itu__package__
untukpack.subpack
akan membiarkan Anda melakukanfrom ..module import something
untuk impor sesuatu daripack.module
. Perhatikan bahwa, seperti yang dikatakan dalam dokumentasi, Anda masih harus memiliki paket tingkat atas di jalur sistem. Ini sudah merupakan cara kerja untuk modul yang diimpor. Satu-satunya hal yang__package__
dilakukan adalah membiarkan Anda menggunakan perilaku itu untuk skrip yang dieksekusi langsung juga.__package__
dalam skrip yang dieksekusi secara langsung tetapi Sayangnya, saya mendapatkan kesalahan berikut: "Modul induk 'xxx' tidak dimuat, tidak dapat melakukan impor relatif"Anda dapat menggunakan
import components.core
secara langsung jika Anda menambahkan direktori saat ini kesys.path
:sumber
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
ini juga akan bekerjafrom os import sys
sepertinya curang :)sys.path
- induk dari direktori file saat ini.import sys, os.path as path
.import os; os.sys.path.append(os.path.dirname(os.path.abspath('.')))
. Kemudian langsungimport components.core
bekerja untuk saya, mengimpor dari direktori induk notebook seperti yang diinginkan.Itu tergantung pada bagaimana Anda ingin meluncurkan skrip Anda.
Jika Anda ingin meluncurkan UnitTest Anda dari baris perintah dengan cara klasik, yaitu:
Kemudian, karena dalam kasus ini 'komponen' dan 'tes' adalah folder saudara, Anda dapat mengimpor modul relatif baik menggunakan sisipan atau metode append dari modul sys.path . Sesuatu seperti:
Jika tidak, Anda dapat meluncurkan skrip Anda dengan argumen '-m' (perhatikan bahwa dalam kasus ini, kita berbicara tentang sebuah paket, dan dengan demikian Anda tidak boleh memberikan ekstensi '.py' ), yaitu:
Dalam kasus seperti itu, Anda cukup menggunakan impor relatif seperti yang Anda lakukan:
Anda akhirnya dapat mencampur dua pendekatan, sehingga skrip Anda akan berfungsi tidak peduli bagaimana namanya. Sebagai contoh:
sumber
python -m pdb myscript.py
untuk meluncurkan sesi debugging.import pdb; pdb.set_trace()
kode ke (inline).insert
daripadaappend
? Yaitu,sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
Di core_test.py, lakukan hal berikut:
sumber
Jika use case Anda adalah untuk menjalankan tes, dan tampaknya benar, maka Anda dapat melakukan hal berikut. Alih-alih menjalankan skrip pengujian Anda seperti
python core_test.py
menggunakan kerangka pengujian sepertipytest
. Kemudian pada baris perintah Anda bisa masukItu akan menjalankan tes di direktori Anda. Ini mengatasi masalah
__name__
keberadaan__main__
yang ditunjukkan oleh @BrenBarn. Selanjutnya, masukkan__init__.py
file kosong ke direktori tes Anda, ini akan membuat bagian direktori tes paket Anda. Maka Anda akan dapat melakukannyaNamun, jika Anda menjalankan skrip pengujian sebagai program utama, maka semuanya akan gagal lagi. Jadi gunakan saja test runner. Mungkin ini juga bekerja dengan pelari tes lain seperti
nosetests
tetapi saya belum memeriksanya. Semoga ini membantu.sumber
Perbaikan cepat saya adalah menambahkan direktori ke path:
sumber
Masalahnya adalah dengan metode pengujian Anda,
Anda mencoba
python core_test.py
maka Anda akan mendapatkan kesalahan ini ValueError: Upaya impor relatif non-paket
Alasan: Anda menguji kemasan Anda dari sumber non-paket.
jadi uji modul Anda dari sumber paket.
jika ini adalah struktur proyek Anda,
cd pkg
atau dari luar pkg /
tunggal
.
jika Anda ingin mengimpor dari folder di direktori yang sama. untuk setiap langkah kembali tambahkan satu lagi.di
how.py
memetikan jika Anda ingin mengimpor bagaimana dari hello.py
sumber
from .. import how
, bagaimana Anda mengimpor kelas / metode tertentu dari file 'how'. ketika saya melakukan hal yang sama denganfrom ..how import foo
itu saya mendapatkan "percobaan impor relatif di luar paket tingkat atas"Utas lama. Saya menemukan bahwa menambahkan
__all__= ['submodule', ...]
ke __init__.py berkas dan kemudian menggunakanfrom <CURRENT_MODULE> import *
target bekerja dengan baik.sumber
Anda dapat menggunakan
from pkg.components.core import GameLoopEvents
, misalnya saya menggunakan pycharm, di bawah ini adalah gambar struktur proyek saya, saya hanya mengimpor dari paket root, lalu berfungsi:sumber
Seperti yang dikatakan Paolo , kami memiliki 2 metode doa:
Satu perbedaan di antara mereka adalah string sys.path [0]. Karena penafsiran akan mencari sys.path ketika melakukan impor , kita dapat melakukannya dengan
tests/core_test.py
:Dan lebih banyak lagi setelah ini, kita dapat menjalankan core_test.py dengan metode lain:
Catatan, py36 hanya diuji.
sumber
Pendekatan ini bekerja untuk saya dan kurang berantakan daripada beberapa solusi:
Direktori induk ada di PYTHONPATH saya, dan ada
__init__.py
file di direktori induk dan direktori ini.Hal di atas selalu bekerja di python 2, tetapi python 3 kadang-kadang menekan ImportError atau ModuleNotFoundError (yang terakhir adalah baru dalam python 3.6 dan subkelas ImportError), sehingga tweak berikut bekerja untuk saya di kedua python 2 dan 3:
sumber
Coba ini
sumber
Jika seseorang mencari solusi, saya menemukan satu. Inilah sedikit konteksnya. Saya ingin menguji salah satu metode yang saya miliki di file. Ketika saya menjalankannya dari dalam
selalu mengeluhkan impor relatif. Saya mencoba menerapkan solusi di atas, tetapi gagal berfungsi, karena ada banyak file bersarang, masing-masing dengan beberapa impor.
Inilah yang saya lakukan. Saya baru saja membuat peluncur, program eksternal yang akan mengimpor metode yang diperlukan dan memanggil mereka. Padahal, bukan solusi yang bagus, itu berhasil.
sumber
Inilah satu cara yang akan membuat marah semua orang tetapi bekerja dengan cukup baik. Dalam tes dijalankan:
Kemudian hanya mengimpor komponen seperti biasa.
sumber
Ini sangat membingungkan, dan jika Anda menggunakan IDE seperti pycharm, ini sedikit membingungkan. Apa yang berhasil untuk saya: 1. Buat pengaturan proyek pycharm (jika Anda menjalankan python dari VE atau dari direktori python) 2. Tidak ada yang salah dengan cara Anda mendefinisikan. kadang-kadang berfungsi dengan dari folder1.file1 kelas impor
jika tidak bekerja, gunakan import folder1.file1 3. Variabel lingkungan Anda harus disebutkan dengan benar dalam sistem atau berikan dalam argumen baris perintah Anda.
sumber
Karena kode Anda berisi
if __name__ == "__main__"
, yang tidak diimpor sebagai paket, Anda sebaiknya menggunakansys.path.append()
untuk menyelesaikan masalah.sumber
if __name__ == "__main__"
dalam file Anda membuat perbedaan untuk apa pun yang terkait dengan mengimpor.