Anda sedang menggunakan from bar import a
. a
menjadi simbol dalam lingkup global modul pengimporan (atau ruang lingkup apa pun tempat pernyataan impor terjadi).
Saat Anda menetapkan nilai baru a
, Anda hanya mengubah a
poin nilai mana juga, bukan nilai sebenarnya. Mencoba untuk mengimpor bar.py
langsung dengan import bar
di __init__.py
dan melakukan percobaan di sana dengan pengaturan bar.a = 1
. Dengan cara ini, Anda benar-benar akan memodifikasi bar.__dict__['a']
yang merupakan nilai 'nyata' a
dalam konteks ini.
Ini sedikit berbelit-belit dengan tiga lapisan tetapi bar.a = 1
mengubah nilai a
dalam modul yang disebut bar
yang sebenarnya berasal __init__.py
. Itu tidak mengubah nilai a
yang foobar
dilihat karena foobar
tinggal di file yang sebenarnya bar.py
. Anda dapat mengaturnya bar.bar.a
jika ingin mengubahnya.
Ini adalah salah satu bahaya menggunakan from foo import bar
bentuk import
pernyataan: itu terbagi bar
menjadi dua simbol, satu terlihat secara global dari dalam foo
yang dimulai menunjuk ke nilai asli dan simbol yang berbeda terlihat dalam ruang lingkup di manaimport
pernyataan itu dijalankan. Mengubah tempat titik simbol tidak mengubah nilai yang ditunjukkannya juga.
Hal semacam ini sangat mematikan ketika mencoba reload
modul dari interpreter interaktif.
bar.bar.a
pendekatan ini tidak akan banyak membantu dalam kebanyakan kasus penggunaan. Mungkin ide yang lemah untuk menggabungkan kompilasi atau pemuatan modul dan tugas waktu proses karena Anda akan membingungkan diri sendiri (atau orang lain yang menggunakan kode Anda). Terutama dalam bahasa yang berperilaku agak tidak konsisten tentangnya, seperti yang bisa dibilang python.Salah satu sumber kesulitan dengan pertanyaan ini adalah bahwa Anda memiliki sebuah program bernama
bar/bar.py
:import bar
impor baikbar/__init__.py
ataubar/bar.py
, tergantung di mana hal itu dilakukan, yang membuatnya sedikit rumit untuk melacak yanga
merupakanbar.a
.Berikut cara kerjanya:
Kunci untuk memahami apa yang terjadi adalah dengan menyadari bahwa dalam
__init__.py
,pada dasarnya melakukan sesuatu seperti
dan mendefinisikan variabel baru (
bar/__init__.py:a
, jika Anda mau). Jadi, namafrom bar import a
in__init__.py
mengikat Andabar/__init__.py:a
kebar.py:a
objek asli (None
). Inilah mengapa Anda dapat melakukannyafrom bar import a as a2
di__init__.py
: dalam kasus ini, jelas bahwa Anda memiliki keduanyabar/bar.py:a
dan nama variabel yang berbedabar/__init__.py:a2
(dalam kasus Anda, nama kedua variabel kebetulan saja keduanyaa
, tetapi mereka masih hidup di ruang nama yang berbeda: di__init__.py
, merekabar.a
dana
).Sekarang, saat Anda melakukannya
Anda mengakses variabel
bar/__init__.py:a
(karenaimport bar
mengimpor Andabar/__init__.py
). Ini adalah variabel yang Anda ubah (menjadi 1). Anda tidak menyentuh isi variabelbar/bar.py:a
. Jadi saat Anda selanjutnya melakukannyaAnda memanggil
bar/bar.py:foobar()
, yang mengakses variabela
daribar/bar.py
, yang masihNone
(ketikafoobar()
ditentukan, itu mengikat nama variabel sekali dan untuk semua, jadia
inbar.py
adalahbar.py:a
, bukana
variabel lain yang ditentukan dalam modul lain — karena mungkin ada banyaka
variabel di semua modul yang diimpor ). KarenanyaNone
keluaran terakhir .Kesimpulan: yang terbaik adalah menghindari ambiguitas apa pun
import bar
, dengan tidak memilikibar/bar.py
modul apa pun (karenabar.__init__.py
membuat direktori sudahbar/
menjadi paket, yang juga dapat Anda imporimport bar
).sumber
Dengan kata lain: Ternyata kesalahpahaman ini sangat mudah dilakukan. Ini secara diam-diam didefinisikan dalam referensi bahasa Python: penggunaan objek alih-alih simbol . Saya menyarankan agar referensi bahasa Python membuat ini lebih jelas dan tidak terlalu jarang ..
NAMUN:
Saat Anda mengimpor, Anda mengimpor nilai saat ini dari simbol yang diimpor dan menambahkannya ke namespace Anda seperti yang ditentukan. Anda tidak mengimpor referensi, Anda mengimpor nilai secara efektif.
Jadi, untuk mendapatkan nilai yang diperbarui
i
, Anda harus mengimpor variabel yang memiliki referensi ke simbol itu.Dengan kata lain, mengimpor TIDAK seperti
import
di JAVA,external
deklarasi di C / C ++ atau bahkanuse
klausa di PERL.Sebaliknya, pernyataan berikut dengan Python:
lebih seperti kode berikut di K&R C:
(peringatan: dalam kasus Python, "a" dan "x" pada dasarnya adalah referensi ke nilai sebenarnya: Anda tidak menyalin INT, Anda menyalin alamat referensi)
sumber
import
jauh lebih bersih daripada Java, karena namespace / cakupan harus selalu dipisahkan dengan benar dan tidak pernah saling mengganggu dengan cara yang tidak terduga. Seperti di sini: Mengubah pengikatan objek menjadi nama di namespace (baca: memasukkan sesuatu ke properti global modul) tidak pernah memengaruhi namespace lain (baca: referensi yang diimpor) dengan Python. Tapi melakukannya di Java, dll. Dengan Python Anda hanya perlu memahami apa yang diimpor, sedangkan di Java, Anda juga harus memahami modul lain jika nanti akan mengubah nilai yang diimpor ini.