Saya telah menjawab pertanyaan tentang impor absolut dalam Python, yang saya pikir saya mengerti berdasarkan membaca changelog Python 2.5 dan menyertai PEP . Namun, setelah menginstal Python 2.5 dan mencoba membuat contoh penggunaan yang benar from __future__ import absolute_import
, saya menyadari hal-hal yang tidak begitu jelas.
Langsung dari changelog yang ditautkan di atas, pernyataan ini secara akurat merangkum pemahaman saya tentang perubahan impor absolut:
Katakanlah Anda memiliki direktori paket seperti ini:
pkg/ pkg/__init__.py pkg/main.py pkg/string.py
Ini mendefinisikan paket bernama
pkg
berisipkg.main
danpkg.string
submodules.Pertimbangkan kode dalam modul main.py. Apa yang terjadi jika mengeksekusi pernyataan
import string
? Dalam Python 2.4 dan sebelumnya, pertama-tama akan melihat direktori paket untuk melakukan impor relatif, menemukan pkg / string.py, mengimpor konten file itu sebagaipkg.string
modul, dan modul itu terikat dengan nama"string"
dipkg.main
namespace modul.
Jadi saya membuat struktur direktori yang tepat ini:
$ ls -R
.:
pkg/
./pkg:
__init__.py main.py string.py
__init__.py
dan string.py
kosong. main.py
berisi kode berikut:
import string
print string.ascii_uppercase
Seperti yang diharapkan, menjalankan ini dengan Python 2.5 gagal dengan AttributeError
:
$ python2.5 pkg/main.py
Traceback (most recent call last):
File "pkg/main.py", line 2, in <module>
print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'
Namun, lebih jauh di dalam changelog 2.5, kami menemukan ini (penekanan ditambahkan):
Dalam Python 2.5, Anda bisa mengubah
import
perilaku menjadi impor absolut menggunakanfrom __future__ import absolute_import
arahan. Perilaku impor absolut ini akan menjadi default di versi yang akan datang (mungkin Python 2.7). Setelah impor absolut adalah default,import string
akan selalu menemukan versi perpustakaan standar.
Dengan demikian saya dibuat pkg/main2.py
, identik dengan main.py
tetapi dengan arahan impor tambahan di masa depan. Sekarang terlihat seperti ini:
from __future__ import absolute_import
import string
print string.ascii_uppercase
Menjalankan ini dengan Python 2.5, namun ... gagal dengan AttributeError
:
$ python2.5 pkg/main2.py
Traceback (most recent call last):
File "pkg/main2.py", line 3, in <module>
print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'
Ini cukup bertentangan dengan pernyataan yang import string
akan selalu menemukan versi std-lib dengan impor absolut diaktifkan. Terlebih lagi, meskipun ada peringatan bahwa impor absolut dijadwalkan untuk menjadi perilaku "default baru", saya mengalami masalah yang sama menggunakan kedua Python 2.7, dengan atau tanpa __future__
arahan:
$ python2.7 pkg/main.py
Traceback (most recent call last):
File "pkg/main.py", line 2, in <module>
print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'
$ python2.7 pkg/main2.py
Traceback (most recent call last):
File "pkg/main2.py", line 3, in <module>
print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'
serta Python 3.5, dengan atau tanpa (dengan asumsi print
pernyataan diubah di kedua file):
$ python3.5 pkg/main.py
Traceback (most recent call last):
File "pkg/main.py", line 2, in <module>
print(string.ascii_uppercase)
AttributeError: module 'string' has no attribute 'ascii_uppercase'
$ python3.5 pkg/main2.py
Traceback (most recent call last):
File "pkg/main2.py", line 3, in <module>
print(string.ascii_uppercase)
AttributeError: module 'string' has no attribute 'ascii_uppercase'
Saya sudah menguji variasi lain ini. Alih-alih string.py
, saya telah membuat modul kosong - direktori bernama string
hanya berisi kosong __init__.py
- dan bukannya mengeluarkan impor dari main.py
, saya harus cd
ke pkg
dan menjalankan impor langsung dari REPL. Tidak satu pun dari variasi ini (atau kombinasi keduanya) yang mengubah hasil di atas. Saya tidak bisa mendamaikan ini dengan apa yang saya baca tentang __future__
petunjuk dan impor absolut.
Tampaknya bagi saya ini mudah dijelaskan oleh yang berikut (ini dari Python 2 docs tetapi pernyataan ini tetap tidak berubah dalam docs yang sama untuk Python 3):
sys.path
(...)
Seperti diinisialisasi pada startup program, item pertama dari daftar ini
path[0]
,, adalah direktori yang berisi skrip yang digunakan untuk memanggil juru bahasa Python. Jika direktori skrip tidak tersedia (mis. Jika juru bahasa dipanggil secara interaktif atau jika skrip dibaca dari input standar),path[0]
adalah string kosong, yang mengarahkan Python untuk mencari modul dalam direktori saat ini terlebih dahulu.
Jadi apa yang saya lewatkan? Mengapa __future__
pernyataan itu tampaknya tidak melakukan apa yang dikatakannya, dan apa resolusi dari kontradiksi antara dua bagian dokumentasi ini, serta antara perilaku yang digambarkan dan yang sebenarnya?