Script vs. Modul
Berikut penjelasannya. Versi singkatnya adalah bahwa ada perbedaan besar antara langsung menjalankan file Python, dan mengimpor file itu dari tempat lain. Hanya mengetahui di mana direktori file tidak menentukan paket apa yang menurut Python masuk. Selain itu, tergantung pada bagaimana Anda memuat file ke Python (dengan menjalankan atau dengan mengimpor).
Ada dua cara untuk memuat file Python: sebagai skrip tingkat atas, atau sebagai modul. File dimuat sebagai skrip tingkat atas jika Anda menjalankannya secara langsung, misalnya dengan mengetik python myfile.py
pada baris perintah. Itu dimuat sebagai modul jika Anda melakukannya python -m myfile
, atau jika dimuat ketika import
pernyataan dijumpai di dalam beberapa file lain. Hanya ada satu skrip tingkat atas pada satu waktu; skrip tingkat atas adalah file Python yang Anda jalankan untuk memulai sesuatu.
Penamaan
Ketika sebuah file dimuat, ia diberi nama (yang disimpan dalam __name__
atributnya). Jika dimuat sebagai skrip tingkat atas, namanya adalah __main__
. Jika itu dimuat sebagai modul, namanya adalah nama file, didahului dengan nama paket / subpackages yang merupakan bagiannya, dipisahkan oleh titik-titik.
Jadi misalnya dalam contoh Anda:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleA.py
jika Anda mengimpor moduleX
(catatan: diimpor , tidak langsung dieksekusi), namanya akan menjadi package.subpackage1.moduleX
. Jika Anda mengimpor moduleA
, namanya akan menjadi package.moduleA
. Namun, jika Anda langsung lari moduleX
dari baris perintah, namanya akan menjadi __main__
, dan jika Anda langsung lari moduleA
dari baris perintah, namanya akan menjadi __main__
. Ketika sebuah modul dijalankan sebagai skrip tingkat atas, ia kehilangan nama normalnya dan namanya adalah sebaliknya __main__
.
Mengakses modul TIDAK melalui paketnya
Ada kerutan tambahan: nama modul tergantung pada apakah modul itu diimpor "langsung" dari direktori tempatnya, atau diimpor melalui paket. Ini hanya membuat perbedaan jika Anda menjalankan Python di direktori, dan mencoba mengimpor file di direktori yang sama (atau subdirektori dari itu). Misalnya, jika Anda memulai juru bahasa Python di direktori package/subpackage1
dan kemudian melakukannya import moduleX
, nama moduleX
hanya akan moduleX
, dan tidak package.subpackage1.moduleX
. Ini karena Python menambahkan direktori saat ini ke jalur pencarian saat startup; jika ia menemukan modul yang akan diimpor di direktori saat ini, ia tidak akan tahu bahwa direktori itu adalah bagian dari paket, dan informasi paket tidak akan menjadi bagian dari nama modul.
Kasus khusus adalah jika Anda menjalankan interpreter secara interaktif (misalnya, cukup ketik python
dan mulai memasukkan kode Python dengan cepat). Dalam hal ini nama sesi interaktif itu adalah __main__
.
Sekarang di sini adalah hal penting untuk pesan kesalahan Anda: jika nama modul tidak memiliki titik, itu tidak dianggap sebagai bagian dari paket . Tidak masalah di mana file itu sebenarnya ada di disk. Yang penting adalah apa namanya, dan namanya tergantung pada bagaimana Anda memuatnya.
Sekarang lihat kutipan yang Anda masukkan dalam pertanyaan Anda:
Impor relatif menggunakan atribut nama modul untuk menentukan posisi modul dalam hierarki paket. Jika nama modul tidak mengandung informasi paket apa pun (misalnya diatur ke 'utama') maka impor relatif diselesaikan seolah-olah modul tersebut adalah modul tingkat atas, terlepas dari di mana letak sebenarnya modul pada sistem file.
Impor relatif ...
Impor relatif menggunakan modul nama untuk menentukan di mana itu adalah dalam sebuah paket. Saat Anda menggunakan impor relatif seperti from .. import foo
, titik-titik menunjukkan untuk meningkatkan beberapa level dalam hirarki paket. Misalnya, jika nama modul Anda saat ini adalah package.subpackage1.moduleX
, maka ..moduleA
itu berarti package.moduleA
. Agar from .. import
dapat bekerja, nama modul harus memiliki setidaknya titik sebanyak yang ada dalam import
pernyataan.
... hanya relatif dalam satu paket
Namun, jika nama modul Anda __main__
, itu tidak dianggap dalam sebuah paket. Namanya tidak memiliki titik, dan karena itu Anda tidak dapat menggunakan from .. import
pernyataan di dalamnya. Jika Anda mencoba melakukannya, Anda akan mendapatkan kesalahan "relatif-impor dalam paket".
Skrip tidak dapat mengimpor relatif
Apa yang mungkin Anda lakukan adalah Anda mencoba menjalankan moduleX
atau sejenisnya dari baris perintah. Ketika Anda melakukan ini, namanya ditetapkan ke __main__
, yang berarti bahwa impor relatif di dalamnya akan gagal, karena namanya tidak mengungkapkan bahwa itu ada dalam paket. Perhatikan bahwa ini juga akan terjadi jika Anda menjalankan Python dari direktori yang sama di mana modul berada, dan kemudian mencoba mengimpor modul itu, karena, seperti yang dijelaskan di atas, Python akan menemukan modul dalam direktori saat ini "terlalu dini" tanpa disadari. bagian dari paket.
Juga ingat bahwa ketika Anda menjalankan juru bahasa interaktif, "nama" dari sesi interaktif itu selalu __main__
. Dengan demikian Anda tidak dapat melakukan impor relatif langsung dari sesi interaktif . Impor relatif hanya untuk digunakan dalam file modul.
Dua solusi:
Jika Anda benar-benar ingin menjalankan moduleX
secara langsung, tetapi Anda tetap ingin itu dianggap sebagai bagian dari paket, Anda dapat melakukannya python -m package.subpackage1.moduleX
. The -m
memberitahu Python untuk memuatnya sebagai modul, tidak seperti naskah tingkat atas.
Atau mungkin Anda sebenarnya tidak ingin menjalankan moduleX
, Anda hanya ingin menjalankan beberapa skrip lain, misalnya myfile.py
, yang menggunakan fungsi di dalamnya moduleX
. Jika demikian, letakkan di myfile.py
tempat lain - tidak di dalam package
direktori - dan jalankan. Jika di dalam myfile.py
Anda melakukan hal-hal seperti from package.moduleA import spam
, itu akan berfungsi dengan baik.
Catatan
Untuk salah satu dari solusi ini, direktori paket ( package
dalam contoh Anda) harus dapat diakses dari jalur pencarian modul Python ( sys.path
). Jika tidak, Anda tidak akan dapat menggunakan apa pun dalam paket dengan andal.
Sejak Python 2.6, "nama" modul untuk keperluan resolusi paket ditentukan tidak hanya oleh __name__
atributnya tetapi juga oleh __package__
atributnya. Itu sebabnya saya menghindari menggunakan simbol eksplisit __name__
untuk merujuk pada "nama" modul. Karena Python 2.6 modul "nama" modul secara efektif __package__ + '.' + __name__
, atau hanya __name__
jika __package__
ada None
.)