ImportError: X adı içe aktarılamıyor


540

Dört farklı dosyam var: ana, vektör, varlık ve fizik. Ben tüm kodu, sadece ithalat göndereceğiz, çünkü ben hata burada olduğunu düşünüyorum. (İsterseniz daha fazlasını gönderebilirim)

Ana:

import time
from entity import Ent
from vector import Vect
#the rest just creates an entity and prints the result of movement

Varlık:

from vector import Vect
from physics import Physics
class Ent:
    #holds vector information and id
def tick(self, dt):
    #this is where physics changes the velocity and position vectors

Vektör:

from math import *
class Vect:
    #holds i, j, k, and does vector math

Fizik:

from entity import Ent
class Physics:
    #physics class gets an entity and does physics calculations on it.

Sonra main.py çalıştırın ve aşağıdaki hatayı alıyorum:

Traceback (most recent call last):
File "main.py", line 2, in <module>
    from entity import Ent
File ".../entity.py", line 5, in <module>
    from physics import Physics
File ".../physics.py", line 2, in <module>
    from entity import Ent
ImportError: cannot import name Ent

Python için çok yeniyim ama C ++ ile uzun süre çalıştım. Hatanın varlık iki kez, bir kez ana ve daha sonra fizik ithal nedeniyle olduğunu tahmin ediyorum, ancak bir geçici çözüm bilmiyorum. Biri yardım edebilir mi?


Nerede saklandıkları ve hangi dizinlerde dizin yapısı nedir?
Ben

1
python'da döngü içe aktarma için şu cevaba bir göz atın: stackoverflow.com/questions/7199466/…
Gregor

Genel olarak, yapmak iyi bir kodlama uygulaması değildir from <module> import <name>, ya da from <modlue> import *. Aynı adlı referansların üzerine yazma olasılığını önlemek için modül ad alanı altında içe aktarmak daha iyidir.
Joel Cornett

1
@jsells Sadece kendi sınıfları aramalısınız Entityve Vectoryerine Entve Vectbu tür isimler kısaltmak için hiçbir neden yok. Ve evet, kullanın import vectorve sonra x = vector.Vector(0,0,0).

7
Hey @Kevin, Java'yı daha iyi bildiğinizden beri , yazarın ilk cümlesinin Java'da dairesel bağımlılıkların "oldukça yaygın uygulama" olduğu anlamına geldiği 2008 makalesine dair izleniminiz nedir?
HeyWatchThis

Yanıtlar:


502

Dairesel bağımlı ithalatlarınız var. sınıf tanımlanmadan önce physics.pyiçe aktarılır ve zaten başlatılmakta olan içe aktarmaya çalışır . Bağımlılığı yok gelen modül.entityEntphysicsentityphysicsentity


5
Kodunuzu yeniden düzenlemekten daha fazlasını yapabilirsiniz. Ent yapıcı tanımındaki Fizik bölümüne başvurmuyorsanız, mport'u Ent'in hemen altına taşıyın. Bunu yaparsanız, kurucudan sonra içe aktarmayı etkinleştirmek için setPhysics gibi bir yöntem ekleyin.
Teemu Ikonen

12
@jsells C ++ ile "uzun zamandır" çalıştığınızdan, iki sınıfın ASLA birbirine bağımlı olmaması gerektiğini bilmelisiniz. Bu C ++ 'da son derece önemlidir ve Python'daki # 1 şey olmasa bile, bu kuralı takip etmek gerçekten iyi bir fikirdir. Asla birbirini tanıyan iki dersiniz olmaz. Sınıflarınız için yapı oluşturma konusunda yardıma ihtiyacınız varsa, kodun geri kalanını da gönderin. Tam olarak nasıl (kod bakımından) olan Entityve Physicsbirbirine bağlı? Eminim yapmaya çalıştığınız bir çözüm var.

7
@ user2032433 Bu gerçekten 'birbirinizi tanıyın' ile ne demek istediğinize bağlı. İyi tasarımın genellikle tek yönlü bağımlılıklar içeren bir ağaç ürettiği doğrudur ve bu normalde en iyi yaklaşımdır. Ama bunun istisnaları var. C ++ sınıfları kesinlikle birbirlerini dairesel olarak ifade edebilir. (Birbirlerinden oluşmaları imkansız olsa da.) İleri bildirme olmadan, bu her zaman bir C ++ çözümü olmayan Python'da bir sorundur.
John McFarlane

93
"İki sınıfın ASLA birbirine bağımlı olmaması" ifadesi saçmalıktır. Nesne yönelimlerinde iki yönlü (çift yönlü) gezinme çok yaygındır. books.google.co.uk/…
Martin Spamer

5
Durum tasarım modeli (örneğin) genellikle bir Context sınıfı ve bir State arabirimi ile uygulanır. State örnekleri, setState öğesini çağırabilmeleri için Context örneğinden geçirilir. Bu, Devletin Bağlam hakkında bilmesini ve tam tersini gerektirir. Bu klasik yapı nasıl "kodda kötü"? Aslında Python'da güreştiğim problem tam olarak bu, ancak Java'da State'i uyguladığımda bunu yapmak zorunda değildim.
Auspice

141

Dairesel bağımlılıklardan kesinlikle kaçınmanız gerekirken, python'daki ithalatı erteleyebilirsiniz.

Örneğin:

import SomeModule

def someFunction(arg):
    from some.dependency import DependentClass

bu (en azından bazı durumlarda) hatayı atlatacaktır.


38
dairesel bağımlılıklar en iyi
atlatılır

4
Pep8'e dayanarak, içe aktarma yönteminin içine yerleştirmek iyi bir uygulama değildir
TomSawyer

@TomSawyer Neden?
Kröw

@TomSawyer Bunu tavsiye etmiyorum, ancak sizi bir
bağdan kurtarabilecek

117

Bu dairesel bir bağımlılıktır. Kodda herhangi bir yapısal değişiklik yapılmadan çözülebilir. Sorun, vectorsizden entityderhal kullanıma sunulmasını talep ettiğiniz için veya bunun tersi nedeniyle oluşur . Bu sorunun nedeni, kullanıma hazır olmadan önce modülün içeriğine erişmenizi istemenizdir from x import y. Bu aslında aynı

import x
y = x.y
del x

Python dairesel bağımlılıkları tespit edebilir ve sonsuz ithalat döngüsünü önleyebilir. Esasen tek şey, modül için boş bir yer tutucunun oluşturulmasıdır (yani içeriği yoktur). Dairesel olarak bağımlı modüller derlendikten sonra içe aktarılan modülü günceller. Bu böyle bir şey çalışır.

a = module() # import a

# rest of module

a.update_contents(real_a)

Python'un dairesel bağımlılıklarla çalışabilmesi için import xyalnızca stili kullanmanız gerekir .

import x
class cls:
    def __init__(self):
        self.y = x.y

Artık en üst düzeydeki modülün içeriğinden bahsetmediğiniz için, python aslında dairesel bağımlılığın içeriğine erişmek zorunda kalmadan modülü derleyebilir. Üst seviye derken, fonksiyonların (ör. y = x.y) İçeriğinin aksine derleme sırasında yürütülecek olan satırları kastediyorum . Modül içeriğine erişen statik veya sınıf değişkenleri de sorunlara neden olacaktır.


24

Mantığı açıklığa kavuşturmak çok önemlidir. Bu sorun görünür, çünkü başvuru ölü bir döngü haline gelir.

Mantığı değiştirmek istemiyorsanız, ImportError'a neden olan bazı içe aktarma ifadelerini dosyanın sonuna, örneğin sonuna koyabilirsiniz.

a.py

from test.b import b2

def a1():
    print('a1')
    b2()

b.py

from test.a import a1

def b1():
    print('b1')
    a1()

def b2():
    print('b2')

if __name__ == '__main__':
    b1()

İthalat Hatası alacaksınız: ImportError: cannot import name 'a1'

Ancak, test.b dosyasının konumunu A'dan aşağıdaki gibi değiştirirsek:

a.py

def a1():
    print('a1')
    b2()

from test.b import b2

Ve istediğimizi alabiliriz:

b1
a1
b2

18

Bu dairesel bir bağımlılıktır. İhtiyaç duyduğumuz yerde ithalat modülü veya sınıf veya işlev kullanarak bu sorunu çözebiliriz . bu yaklaşımı kullanırsak, dairesel bağımlılığı düzeltebiliriz

A.py

from B import b2
def a1():
    print('a1')
    b2()

B.py

def b1():
   from A import a1
   print('b1')
   a1()

def b2():
   print('b2')
if __name__ == '__main__':
   b1() 

17

Farklı bir nedenden dolayı da bu hatayı aldım ...

from my_sub_module import my_function

Ana komut dosyasının Windows satır sonları vardı. my_sub_moduleUNIX satır sonlarına sahipti. Bunları aynı olacak şekilde değiştirmek sorunu çözdü. Ayrıca aynı karakter kodlamasına sahip olmaları gerekir.


7

Daha önce de belirtildiği gibi, bu dairesel bir bağımlılıktan kaynaklanmaktadır . Ne söz edilmemiştir Python kullanırken olmasıdır yazarak modülü ve sadece açıklamak için kullanılabilecek bir sınıfını içe Türleri , şunları kullanabilirsiniz İleri referanslar :

Bir tür ipucu henüz tanımlanmamış adlar içerdiğinde, bu tanım daha sonra çözümlenecek bir dize hazır bilgisi olarak ifade edilebilir.

ve bağımlılığı ( içe aktarma ) kaldırın , örneğin

from my_module import Tree

def func(arg: Tree):
    # code

yapmak:

def func(arg: 'Tree'):
    # code

(kaldırılan importifadeye dikkat edin )


6

Mevcut python betiğinize, içe aktardığınız başka bir modülün adını vermeyin

Çözüm: Çalışan Python Komut Dosyanızı Yeniden Adlandırın

Misal:

  1. çalışıyorsun medicaltorch.py
  2. Bu komut şunlara sahip: from medicaltorch import datasets as mt_datasetsnerede medicaltorchyüklü bir modül olması gerekiyordu

Bu ile başarısız olur ImportError. Sadece çalışan python betiğinizi 1'de yeniden adlandırın.


Teşekkürler, bu yaşadığım sorunu çözdü. Colorama kütüphanesini kullandım ve colorama.py dosyasına adını verdim, bu yüzden python ne içe aktaracağını bilmiyordu. Dosya adının değiştirilmesi yardımcı olur.
Marek Bodziony

5

Bunu henüz burada görmeyin - bu inanılmaz derecede aptalca, ancak doğru değişkeni / işlevi içe aktardığınızdan emin olun.

Bu hatayı alıyordum

ImportError: IMPLICIT_WAIT adı içe aktarılamıyor

çünkü benim değişkenim aslında IMPLICIT_TIMEOUT.

içe aktarma işlemimi doğru adı kullanacak şekilde değiştirdiğimde, artık hata mesajı almadım 🤦‍♂️


1
Neden from PIL import Pillowişe yaramadığını anlamaya çalışan birini öldürmeye hazırdım . 😠
aalaap

5

Eğer ithal ediyorsanız file1.pygelen file2.pyve bu kullandı:

if __name__ == '__main__':
    # etc

O in altına Değişkenler file1.py alınamaz için file2.pyçünkü __name__ eşit değildir yapar __main__ !

Eğer bir şey almak istiyorsanız file1.pyiçin file2.py, sen bu kullanmak gerekir file1.py:

if __name__ == 'file1':
    # etc

Şüphe durumunda, bir yapmak assertolmadığını belirlemek için deyimi__name__=='__main__'


4

İçe aktarma hatasını izlemenin bir yolu, kötü dosyayı izlemek için içe aktarılan dosyaların her birinde python çalıştırmaya çalışmaktır.

  1. şöyle bir şey elde edersiniz:

    python ./main.py

    ImportError: A adı alınamıyor

  2. sonra başlatırsınız:

    python ./modules/a.py

    ImportError: B adı alınamıyor

  3. sonra başlatırsınız:

    python ./modules/b.py

    ImportError: C adı içe aktarılamıyor (varolmayan bir modül veya başka bir hata)


3

Ayrıca doğrudan OP ile ilgili değil, ancak bir modüle yeni bir nesne ekledikten sonra bir PyCharm Python konsolunu yeniden başlatamamak da çok kafa karıştırıcı olmanın harika bir yoludur.ImportError: Cannot import name ...

Kafa karıştırıcı kısmı pycharm olmasıdır olacaktır konsolunda ithalat otomatik tamamlamak, ancak ithalat daha sonra başarısız olur.


2

Sorun açık: Modüller ve isimler arasındaki dairesel bağımlılık .entityphysics

Tüm modülü veya sadece bir sınıfı içe aktarmaksızın, adların yüklenmesi gerekir.

Bu örneği izleyin:

# a.py
import b
def foo():
  pass
b.bar()
# b.py
import a
def bar():
  pass
a.foo()

Bu şu şekilde derlenecektir:

# a.py
# import b
# b.py
# import a # ignored, already importing
def bar():
  pass
a.foo()
# name a.foo is not defined!!!
# import b done!
def foo():
  pass
b.bar()
# done!

Küçük bir değişiklikle bunu çözebiliriz:

# a.py
def foo():
  pass
import b
b.bar()
# b.py
def bar():
  pass
import a
a.foo()

Bu şu şekilde derlenecektir:

# a.py
def foo():
  pass
# import b
# b.py
def bar():
  pass
# import a # ignored, already importing
a.foo()
# import b done!
b.bar()
# done!

2

Benim durumumda, bir Jupyter not defterinde çalışıyordum ve bu, çalışma dosyamdaki sınıf / işlevi tanımladığım zamandan itibaren içe aktarma zaten önbelleğe alındığı için oluyordu.

Jupyter çekirdeğimi yeniden başlattım ve hata kayboldu.


1

Özellikle bu asker için değil, ancak aynı hata, içe aktarma işleminizdeki sınıf adının içe aktardığınız dosyadaki tanımla eşleşmediğini gösterir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.