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.pyIni mendefinisikan paket bernama
pkgberisipkg.maindanpkg.stringsubmodules.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.stringmodul, dan modul itu terikat dengan nama"string"dipkg.mainnamespace modul.
Jadi saya membuat struktur direktori yang tepat ini:
$ ls -R
.:
pkg/
./pkg:
__init__.py main.py string.py
__init__.pydan string.pykosong. main.pyberisi 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
importperilaku menjadi impor absolut menggunakanfrom __future__ import absolute_importarahan. Perilaku impor absolut ini akan menjadi default di versi yang akan datang (mungkin Python 2.7). Setelah impor absolut adalah default,import stringakan selalu menemukan versi perpustakaan standar.
Dengan demikian saya dibuat pkg/main2.py, identik dengan main.pytetapi 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 stringakan 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 printpernyataan 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 stringhanya berisi kosong __init__.py- dan bukannya mengeluarkan impor dari main.py, saya harus cdke pkgdan 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?