Jadi saya mendapatkan kesalahan ini
Traceback (most recent call last):
File "/Users/alex/dev/runswift/utils/sim2014/simulator.py", line 3, in <module>
from world import World
File "/Users/alex/dev/runswift/utils/sim2014/world.py", line 2, in <module>
from entities.field import Field
File "/Users/alex/dev/runswift/utils/sim2014/entities/field.py", line 2, in <module>
from entities.goal import Goal
File "/Users/alex/dev/runswift/utils/sim2014/entities/goal.py", line 2, in <module>
from entities.post import Post
File "/Users/alex/dev/runswift/utils/sim2014/entities/post.py", line 4, in <module>
from physics import PostBody
File "/Users/alex/dev/runswift/utils/sim2014/physics.py", line 21, in <module>
from entities.post import Post
ImportError: cannot import name Post
dan Anda dapat melihat bahwa saya menggunakan pernyataan impor yang sama lebih jauh dan berfungsi? Apakah ada aturan tidak tertulis tentang impor melingkar? Bagaimana cara menggunakan kelas yang sama di bawah tumpukan panggilan?
from
sintaks akan selalu berfungsi. Jika saya memilikiclass A(object): pass; class C(b.B): pass
di modul a danclass B(a.A): pass
di modul b maka impor melingkar masih menjadi masalah dan ini tidak akan berhasil.B
ke modula
, atau pindahkan kelasC
ke modulb
sehingga Anda dapat memutus siklus. Perlu juga dicatat bahwa meskipun hanya satu arah lingkaran yang melibatkan kode tingkat atas (misalnya jika kelasC
tidak ada), Anda mungkin mendapatkan kesalahan, bergantung pada modul mana yang diimpor pertama kali oleh kode lain.from . import sibling_module
, tidakfrom .sibling_module import SomeClass
). Ada lebih banyak kehalusan ketika__init__.py
file paket terlibat dalam impor melingkar, tetapi masalahnya jarang terjadi, dan mungkin bug dalamimport
implementasi. Lihat bug Python 23447 , yang saya kirimkan tambalannya (yang sayangnya telah merana).Saat Anda mengimpor modul (atau anggotanya) untuk pertama kali, kode di dalam modul dijalankan secara berurutan seperti kode lainnya; misalnya, tidak diperlakukan berbeda dengan tubuh suatu fungsi. An
import
hanyalah sebuah perintah seperti yang lainnya (tugas, panggilan fungsidef
,,class
). Dengan asumsi impor Anda terjadi di bagian atas skrip, inilah yang terjadi:World
dariworld
,world
skrip dijalankan.world
impor ScriptField
, yang menyebabkanentities.field
script untuk dijalankan.entities.post
skrip karena Anda mencoba untuk mengimporPost
entities.post
penyebab Scriptphysics
modul akan dieksekusi karena mencoba untuk imporPostBody
physics
coba imporPost
darientities.post
entities.post
modul tersebut sudah ada di memori, tetapi itu tidak masalah. Bisa jadi modul tidak ada di memori, atau modul belum memilikiPost
anggota karena belum selesai mengeksekusi untuk mendefinisikanPost
Post
tidak ada untuk diimporJadi tidak, ini tidak "bekerja lebih jauh di tumpukan panggilan". Ini adalah jejak tumpukan tempat terjadinya kesalahan, yang berarti terjadi kesalahan saat mencoba mengimpor
Post
di kelas itu. Anda tidak boleh menggunakan impor melingkar. Paling-paling, itu memiliki manfaat yang dapat diabaikan (biasanya, tidak ada manfaat), dan itu menyebabkan masalah seperti ini. Ini membebani pengembang mana pun yang memeliharanya, memaksa mereka berjalan di atas cangkang telur agar tidak pecah. Refactor organisasi modul Anda.sumber
isinstance(userData, Post)
. Terlepas dari itu, Anda tidak punya pilihan. Impor melingkar tidak akan berfungsi. Fakta bahwa Anda memiliki impor melingkar adalah bau kode bagi saya. Ini menyarankan Anda memiliki beberapa fungsionalitas yang harus dipindahkan ke modul ketiga. Saya tidak bisa mengatakan apa tanpa melihat kedua kelas.def
tidak dijalankan hingga fungsi dipanggil, jadi impor tidak akan terjadi hingga Anda benar-benar memanggil fungsi tersebut. Pada saat itu,import
s harus berfungsi karena salah satu modul akan sepenuhnya diimpor sebelum panggilan. Itu adalah peretasan yang benar-benar menjijikkan, dan itu tidak boleh berada di basis kode Anda untuk jangka waktu yang lama.import foo
lebih darifrom foo import Bar
. Itu karena kebanyakan modul hanya mendefinisikan hal-hal (seperti fungsi dan kelas) yang berjalan nanti. Modul yang melakukan hal-hal penting saat Anda mengimpornya (seperti skrip yang tidak dilindungi olehif __name__ == "__main__"
) mungkin masih menjadi masalah, tetapi itu tidak terlalu umum.Untuk memahami dependensi melingkar, Anda perlu ingat bahwa Python pada dasarnya adalah bahasa scripting. Eksekusi pernyataan di luar metode terjadi pada waktu kompilasi. Pernyataan impor dijalankan seperti pemanggilan metode, dan untuk memahaminya Anda harus memikirkannya seperti pemanggilan metode.
Saat Anda melakukan impor, apa yang terjadi bergantung pada apakah file yang Anda impor sudah ada di tabel modul. Jika ya, Python menggunakan apa pun yang saat ini ada di tabel simbol. Jika tidak, Python mulai membaca file modul, mengkompilasi / mengeksekusi / mengimpor apa pun yang ditemukannya di sana. Simbol yang direferensikan pada waktu kompilasi ditemukan atau tidak, bergantung pada apakah simbol telah dilihat, atau belum dilihat oleh kompilator.
Bayangkan Anda memiliki dua file sumber:
Berkas X.py
Berkas Y.py
Sekarang misalkan Anda mengkompilasi file X.py. Kompilator memulai dengan mendefinisikan metode X1, dan kemudian menekan pernyataan import di X.py. Ini menyebabkan kompilator menghentikan sementara kompilasi X.py dan mulai mengkompilasi Y.py. Tak lama kemudian kompilator menekan pernyataan import di Y.py. Karena X.py sudah ada di tabel modul, Python menggunakan tabel simbol X.py yang tidak lengkap untuk memenuhi semua referensi yang diminta. Simbol apapun yang muncul sebelum pernyataan import di X.py sekarang ada di tabel simbol, tapi simbol apapun setelahnya tidak. Karena X1 sekarang muncul sebelum pernyataan impor, itu berhasil diimpor. Python kemudian melanjutkan kompilasi Y.py. Dengan melakukan itu, ia mendefinisikan Y2 dan menyelesaikan kompilasi Y.py. Kemudian melanjutkan kompilasi X.py, dan menemukan Y2 di tabel simbol Y.py. Kompilasi akhirnya selesai tanpa kesalahan.
Sesuatu yang sangat berbeda terjadi jika Anda mencoba mengkompilasi Y.py dari baris perintah. Saat mengkompilasi Y.py, kompilator menekan pernyataan import sebelum mendefinisikan Y2. Kemudian ia mulai mengkompilasi X.py. Segera muncul pernyataan import di X.py yang membutuhkan Y2. Tapi Y2 tidak terdefinisi, jadi kompilasi gagal.
Harap perhatikan bahwa jika Anda memodifikasi X.py untuk mengimpor Y1, kompilasi akan selalu berhasil, apa pun file yang Anda kompilasi. Namun jika Anda memodifikasi file Y.py untuk mengimpor simbol X2, tidak ada file yang akan dikompilasi.
Kapan pun modul X, atau modul apa pun yang diimpor oleh X mungkin mengimpor modul saat ini, JANGAN gunakan:
Setiap kali Anda merasa mungkin ada impor melingkar, Anda juga harus menghindari referensi waktu kompilasi ke variabel di modul lain. Pertimbangkan kode yang tampak tidak bersalah:
Misalkan modul X mengimpor modul ini sebelum modul ini mengimpor X. Selanjutnya anggaplah Y didefinisikan dalam X setelah pernyataan import. Maka Y tidak akan ditentukan ketika modul ini diimpor, dan Anda akan mendapatkan kesalahan kompilasi. Jika modul ini mengimpor Y terlebih dahulu, Anda bisa lolos begitu saja. Namun jika salah satu rekan kerja Anda dengan polosnya mengubah urutan definisi di modul ketiga, kode tersebut akan rusak.
Dalam beberapa kasus, Anda dapat menyelesaikan dependensi melingkar dengan memindahkan pernyataan import ke bawah definisi simbol yang dibutuhkan oleh modul lain. Dalam contoh di atas, definisi sebelum pernyataan import tidak pernah gagal. Definisi setelah pernyataan import terkadang gagal, tergantung pada urutan kompilasi. Anda bahkan dapat meletakkan pernyataan import di akhir file, selama tidak ada simbol yang diimpor diperlukan pada waktu kompilasi.
Perhatikan bahwa memindahkan pernyataan import ke bawah dalam modul mengaburkan apa yang Anda lakukan. Ganti rugi ini dengan komentar di bagian atas modul Anda seperti berikut ini:
Secara umum ini adalah praktik yang buruk, tetapi terkadang sulit untuk dihindari.
sumber
Bagi Anda yang, seperti saya, datang ke masalah ini dari Django, Anda harus tahu bahwa dokumen menyediakan solusi: https://docs.djangoproject.com/en/1.10/ref/models/fields/#foreignkey
"... Untuk merujuk ke model yang ditentukan dalam aplikasi lain, Anda dapat secara eksplisit menentukan model dengan label aplikasi lengkap. Misalnya, jika model Pabrikan di atas ditentukan dalam aplikasi lain yang disebut produksi, Anda perlu menggunakan:
Referensi semacam ini dapat berguna saat menyelesaikan dependensi impor melingkar antara dua aplikasi. ... "
sumber
Saya dapat mengimpor modul dalam fungsi (hanya) yang akan membutuhkan objek dari modul ini:
sumber
Jika Anda mengalami masalah ini dalam aplikasi yang cukup kompleks, mungkin sulit untuk memfaktor ulang semua impor Anda. PyCharm menawarkan perbaikan cepat untuk ini yang secara otomatis akan mengubah semua penggunaan simbol yang diimpor juga.
sumber
Saya menggunakan yang berikut ini:
tetapi untuk menyingkirkan
circular reference
saya melakukan hal berikut dan berhasil:sumber