Apa yang akan terjadi jika dua modul saling mengimpor?
Untuk menggeneralisasi masalah, bagaimana dengan impor siklik di Python?
Apa yang akan terjadi jika dua modul saling mengimpor?
Untuk menggeneralisasi masalah, bagaimana dengan impor siklik di Python?
Jawaban:
Ada diskusi yang sangat bagus tentang ini di comp.lang.python tahun lalu. Ini menjawab pertanyaan Anda dengan cukup teliti.
sumber
Jika Anda melakukannya
import foo
di dalambar
danimport bar
di dalamfoo
, itu akan berfungsi dengan baik. Pada saat segala sesuatu benar-benar berjalan, kedua modul akan terisi penuh dan akan memiliki referensi satu sama lain.Masalahnya adalah kapan Anda melakukannya
from foo import abc
danfrom bar import xyz
. Karena sekarang setiap modul memerlukan modul lain untuk sudah diimpor (sehingga nama yang kita impor ada) sebelum dapat diimpor.sumber
from foo import *
danfrom bar import *
juga akan berfungsi dengan baik.from x import y
, namun masih mendapatkan kesalahan impor melingkarimport
pernyataan dijalankan. Jadi itu tidak akan kesalahan tetapi Anda mungkin tidak mendapatkan semua variabel yang Anda harapkan.from foo import *
danfrom bar import *
, semua yang dieksekusi difoo
dalam fase inisialisasibar
, dan fungsi sebenarnyabar
belum didefinisikan ...Impor siklik berakhir, tetapi Anda harus berhati-hati untuk tidak menggunakan modul yang diimpor secara siklik selama inisialisasi modul.
Pertimbangkan file-file berikut:
a.py:
b.py:
Jika Anda menjalankan a.py, Anda akan mendapatkan yang berikut:
Pada impor kedua dari b.py (yang kedua
a in
), juru bahasa Python tidak mengimporb
lagi, karena sudah ada dalam modul dikt.Jika Anda mencoba mengakses
b.x
daria
selama inisialisasi modul, Anda akan mendapatkanAttributeError
.Tambahkan baris berikut ke
a.py
:Kemudian, outputnya adalah:
Ini karena modul dieksekusi saat impor dan pada saat
b.x
diakses, saluranx = 3
belum dieksekusi, yang hanya akan terjadi setelahnyab out
.sumber
__name__
bukan'a'
. Pada awalnya, saya benar-benar bingung mengapa file akan dieksekusi dua kali.Seperti jawaban lain yang menggambarkan pola ini dapat diterima dalam python:
Yang akan menghindari pelaksanaan pernyataan impor ketika file diimpor oleh modul lain. Hanya jika ada ketergantungan melingkar logis, ini akan gagal.
Sebagian besar Impor Circular sebenarnya bukan impor melingkar yang logis tetapi lebih meningkatkan
ImportError
kesalahan, karena caraimport()
mengevaluasi pernyataan tingkat atas dari seluruh file ketika dipanggil.Ini
ImportErrors
hampir selalu dapat dihindari jika Anda ingin impor Anda positif :Pertimbangkan impor melingkar ini:
Aplikasi A
Aplikasi B
Dari David Beazleys, Modul dan Paket Pembicaraan yang luar biasa : Live and Let Die! - PyCon 2015 ,,
1:54:00
berikut adalah cara untuk menangani impor melingkar dengan python:Ini mencoba mengimpor
SimplifiedImageSerializer
dan jikaImportError
dinaikkan, karena sudah diimpor, itu akan menariknya dari importcache.PS: Anda harus membaca seluruh kiriman ini dengan suara David Beazley.
sumber
Saya mendapat contoh di sini yang mengejutkan saya!
foo.py
bar.py
main.py
Di baris perintah: $ python main.py
sumber
import bar
difoo.py
akhirbar
danfoo
keduanya harus menggunakangX
, solusi 'terbersih' adalah memasukkangX
modul lain dan memiliki keduanyafoo
danbar
mengimpor modul itu. (terbersih dalam arti bahwa tidak ada dependensi semantik yang tersembunyi.)bar
bahkan tidak dapat menemukangX
di foo. impor melingkar baik-baik saja dengan sendirinya, tetapi hanya saja itugX
tidak ditentukan ketika diimpor.Modul a.py:
Modul b.py
Menjalankan "Modul a" akan menampilkan:
Ini output 3 baris ini sementara itu seharusnya menghasilkan infinitival karena impor melingkar. Apa yang terjadi baris demi baris saat menjalankan "Modul a" tercantum di sini:
import b
. jadi akan mengunjungi modul bimport a
. jadi akan mengunjungi modul aimport b
tetapi perhatikan bahwa baris ini tidak akan dieksekusi lagi , karena setiap file dalam python mengeksekusi baris impor hanya untuk sekali, tidak masalah di mana atau kapan dijalankan. sehingga akan lolos ke baris berikutnya dan mencetak"This is from module a"
."This is from module b"
"This is from module a"
dan program akan selesai.sumber
Saya sepenuhnya setuju dengan jawaban pythoneer di sini. Tetapi saya telah menemukan beberapa kode yang cacat dengan impor melingkar dan menyebabkan masalah ketika mencoba untuk menambahkan tes unit. Jadi untuk menambalnya dengan cepat tanpa mengubah semua yang Anda bisa menyelesaikan masalah dengan melakukan impor dinamis.
Sekali lagi, ini bukan perbaikan permanen tetapi dapat membantu seseorang yang ingin memperbaiki kesalahan impor tanpa mengubah terlalu banyak kode.
Bersulang!
sumber
Ada banyak jawaban bagus di sini. Walaupun biasanya ada solusi cepat untuk masalah ini, beberapa di antaranya terasa lebih pythonic daripada yang lain, jika Anda memiliki kemewahan melakukan beberapa refactoring, pendekatan lain adalah menganalisis organisasi kode Anda, dan mencoba untuk menghapus ketergantungan melingkar. Anda dapat menemukan, misalnya, bahwa Anda memiliki:
File a.py
File b.py
Dalam hal ini, hanya memindahkan satu metode statis ke file terpisah, katakan
c.py
:File c.py
akan memungkinkan menghapus
save_result
metode dari A, dan dengan demikian memungkinkan menghapus impor A dari a di b:File Refactored a.py
File Refactored b.py
Singkatnya, jika Anda memiliki alat (misalnya pylint atau PyCharm) yang melaporkan metode yang bisa statis, hanya melemparkan
staticmethod
dekorator pada mereka mungkin bukan cara terbaik untuk membungkam peringatan. Meskipun metode ini tampaknya terkait dengan kelas, mungkin lebih baik untuk memisahkannya, terutama jika Anda memiliki beberapa modul terkait yang mungkin membutuhkan fungsionalitas yang sama dan Anda bermaksud untuk mempraktikkan prinsip KERING.sumber
Impor sirkuler dapat membingungkan karena impor melakukan dua hal:
Yang pertama dilakukan hanya sekali, sedangkan yang terakhir di setiap pernyataan impor. Impor sirkuler menciptakan situasi ketika mengimpor modul menggunakan modul yang diimpor dengan kode yang dieksekusi sebagian. Karena itu tidak akan melihat objek yang dibuat setelah pernyataan impor. Contoh kode di bawah ini menunjukkannya.
Impor sirkular bukanlah kejahatan utama yang harus dihindari dengan cara apa pun. Dalam beberapa kerangka kerja seperti Flask mereka sangat alami dan mengubah kode Anda untuk menghilangkannya tidak membuat kode lebih baik.
main.py
oleh
a.py
output python main.py dengan komentar
sumber
Saya memecahkan masalah dengan cara berikut, dan berfungsi dengan baik tanpa kesalahan. Pertimbangkan dua file
a.py
danb.py
.Saya menambahkan ini ke
a.py
dan itu berhasil.a.py:
b.py:
Output yang saya dapatkan adalah
sumber
Ok, saya pikir saya punya solusi yang cukup keren. Katakanlah Anda memiliki file
a
dan fileb
. Anda memilikidef
atauclass
dalam fileb
yang ingin Anda gunakan dalam modula
, tetapi Anda memiliki sesuatu yang lain, baikdef
,class
atau variabel dari filea
yang Anda butuhkan dalam definisi Anda atau kelas dalam fileb
. Apa yang dapat Anda lakukan adalah, di bagian bawah filea
, setelah memanggil fungsi atau kelas dalam filea
yang diperlukan dalam fileb
, tetapi sebelum memanggil fungsi atau kelas dari fileb
yang Anda butuhkan untuk filea
, katakanimport b
Lalu, dan inilah bagian kuncinya , dalam semua definisi atau kelas dalam fileb
yang memerlukandef
atauclass
dari filea
(sebut sajaCLASS
), katamufrom a import CLASS
Ini berfungsi karena Anda dapat mengimpor file
b
tanpa Python mengeksekusi salah satu pernyataan impor dalam fileb
, dan dengan demikian Anda menghindari impor melingkar.Sebagai contoh:
Ajukan:
File b:
Voila.
sumber
from a import CLASS
sebenarnya tidak melewatkan mengeksekusi semua kode dalam a.py. Inilah yang sebenarnya terjadi: (1) Semua kode di a.py dijalankan sebagai modul khusus "__main__". (2) Padaimport b
, kode tingkat atas dalam b.py dijalankan (mendefinisikan kelas B) dan kemudian kontrol kembali ke "__main__". (3) "__main__" akhirnya memberikan kontrol kego.dostuff()
. (4) ketika dostuff () munculimport a
, ia menjalankan semua kode dalam a.py lagi , kali ini sebagai modul "a"; kemudian mengimpor objek CLASS dari modul baru "a". Jadi sebenarnya, ini akan bekerja dengan baik jika Anda digunakanimport a
di mana saja di b.py.