ImportError: Không thể nhập tên X


540

Tôi có bốn tệp khác nhau có tên: chính, vector, thực thể và vật lý. Tôi sẽ không đăng tất cả mã, chỉ nhập, vì tôi nghĩ đó là lỗi. (Nếu bạn muốn, tôi có thể đăng thêm)

Chủ yếu:

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

Thực thể:

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

Vectơ:

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

Vật lý:

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

Sau đó tôi chạy từ main.py và tôi gặp lỗi sau:

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

Tôi rất mới với Python nhưng đã làm việc với C ++ trong một thời gian dài. Tôi đoán rằng lỗi là do nhập thực thể hai lần, một lần chính và sau đó trong vật lý, nhưng tôi không biết cách giải quyết. Có ai giúp được không?


Cấu trúc thư mục của nơi chúng được lưu trữ và trong thư mục nào?
Ben

1
hãy xem câu trả lời này để nhập vòng lặp trong python: stackoverflow.com/questions/7199466/ mẹo
Gregor

Nói chung, nó không phải là thực hành mã hóa tốt để làm from <module> import <name>, hoặc from <modlue> import *. Tốt hơn là nhập trong không gian tên mô-đun để ngăn chặn cơ hội ghi đè các tham chiếu có tên giống hệt.
Joel Cornett

1
@jsells Bạn chỉ nên gọi các lớp của mình EntityVectorthay vì EntVect, không có lý do gì để rút ngắn những tên như vậy. Và có, sử dụng import vectorvà sau đó x = vector.Vector(0,0,0).

7
Xin chào @Kevin vì bạn biết Java tốt hơn, ấn tượng của bạn về bài viết năm 2008 này trong đó câu đầu tiên của tác giả đề cập đến cách phụ thuộc vòng tròn là "thực tiễn khá phổ biến" trong Java?
HeyWatch This

Câu trả lời:


502

Bạn có nhập khẩu phụ thuộc tròn. physics.pyđược nhập từ entitytrước khi lớp Entđược định nghĩa và physicscố gắng nhập entityđã được khởi tạo. Loại bỏ sự phụ thuộc vào physicstừ entitymô-đun.


5
Bạn không thể làm gì nhiều hơn là cấu trúc lại mã của mình. Nếu bạn không tham khảo Vật lý trong định nghĩa hàm tạo Ent, hãy di chuyển ngay dưới Ent. Nếu bạn làm như vậy, hãy thêm phương thức như setPhysics để cho phép nhập sau hàm tạo.
Teemu Ikonen

12
@jsells Vì bạn đã làm việc với C ++ "trong một thời gian dài", bạn nên biết rằng hai lớp KHÔNG BAO GIỜ nên phụ thuộc vào nhau. Điều này cực kỳ quan trọng trong C ++ và ngay cả khi đó không phải là điều số 1 trong Python, thì vẫn nên thực hiện theo quy tắc này. Không bao giờ có hai lớp biết nhau. Nếu bạn cần trợ giúp trong việc tạo cấu trúc cho các lớp của mình, hãy đăng phần còn lại của mã. Làm thế nào chính xác (về mã) EntityPhysicsđược liên kết với nhau? Tôi chắc chắn có một cách giải quyết cho những gì bạn đang cố gắng làm.

7
@ user2032433 Điều đó thực sự phụ thuộc vào ý của bạn là 'hiểu nhau'. Đúng là thiết kế tốt thường tạo ra một cây phụ thuộc một chiều và đây thường là cách tiếp cận tốt nhất. Nhưng có những ngoại lệ cho điều này. Các lớp C ++ chắc chắn có thể tham chiếu với nhau theo vòng tròn. (Mặc dù chúng không thể được cấu thành từ nhau.) Không có khai báo chuyển tiếp, đây là một vấn đề trong Python mà không phải lúc nào cũng có giải pháp C ++.
John McFarlane

93
Câu nói "hai lớp KHÔNG BAO GIỜ nên phụ thuộc vào nhau" là rác rưởi. Điều hướng hai chiều (hai chiều) rất phổ biến trong hướng đối tượng. Books.google.co.uk/,
Martin Spamer

5
Mẫu thiết kế Trạng thái (ví dụ) thường được triển khai với lớp Ngữ cảnh và giao diện Trạng thái. Các thể hiện của trạng thái được thông qua thể hiện bối cảnh để họ có thể gọi setState. Điều này đòi hỏi Nhà nước phải biết về Bối cảnh và ngược lại. Làm thế nào là cấu trúc cổ điển này là "xấu về mã"? Trên thực tế, đó chính xác là vấn đề tôi đang vật lộn với Python, nhưng không phải khi tôi triển khai Trạng thái trong Java.
Kiết tường

141

Mặc dù bạn chắc chắn nên tránh phụ thuộc vòng tròn, bạn có thể trì hoãn nhập khẩu trong python.

ví dụ:

import SomeModule

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

điều này (ít nhất là trong một số trường hợp) sẽ tránh được lỗi.


38
phụ thuộc vòng tròn được phá vỡ tốt nhất
ckb

4
Dựa trên pep8, đưa phương thức nhập vào bên trong không phải là cách thực hành tốt
TomSawyer

@TomSawyer Tại sao?
Kröw

@TomSawyer Tôi không khuyên bạn điều này, nhưng đó là một giải pháp nhanh chóng có thể giúp bạn thoát khỏi sự ràng buộc
chia sẻ

117

Đây là một phụ thuộc tròn. Nó có thể được giải quyết mà không có bất kỳ sửa đổi cấu trúc nào đối với mã. Vấn đề xảy ra bởi vì trong vectorbạn yêu cầu entityphải có sẵn để sử dụng ngay lập tức và ngược lại. Lý do cho vấn đề này là do bạn yêu cầu truy cập nội dung của mô-đun trước khi nó sẵn sàng - bằng cách sử dụng from x import y. Điều này về cơ bản giống như

import x
y = x.y
del x

Python có thể phát hiện các phụ thuộc vòng tròn và ngăn chặn vòng lặp vô hạn của nhập khẩu. Về cơ bản, tất cả những gì xảy ra là một trình giữ chỗ trống được tạo cho mô-đun (nghĩa là nó không có nội dung). Khi các mô đun phụ thuộc tuần hoàn được biên dịch, nó sẽ cập nhật mô đun đã nhập. Đây là công trình như thế này.

a = module() # import a

# rest of module

a.update_contents(real_a)

Để python có thể làm việc với các phụ thuộc tròn, bạn chỉ phải sử dụng import xkiểu.

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

Vì bạn không còn đề cập đến nội dung của mô-đun ở cấp cao nhất, python có thể biên dịch mô-đun mà không cần phải truy cập nội dung của phụ thuộc vòng tròn. Theo cấp cao nhất tôi có nghĩa là các dòng sẽ được thực thi trong quá trình biên dịch trái ngược với nội dung của các hàm (ví dụ. y = x.y). Các biến tĩnh hoặc lớp truy cập vào nội dung mô-đun cũng sẽ gây ra vấn đề.


24

Để làm cho logic rõ ràng là rất quan trọng. Vấn đề này xuất hiện, bởi vì tham chiếu trở thành một vòng lặp chết.

Nếu bạn không muốn thay đổi logic, bạn có thể đặt một số câu lệnh nhập đã gây ra ImportError sang vị trí khác của tệp, ví dụ như kết thúc.

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()

Bạn sẽ nhận được Lỗi nhập: ImportError: cannot import name 'a1'

Nhưng nếu chúng ta thay đổi vị trí từ test.b nhập b2 vào A như dưới đây:

a.py

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

from test.b import b2

Và chúng ta có thể có được những gì chúng ta muốn:

b1
a1
b2

18

Đây là một phụ thuộc tròn. chúng ta có thể giải quyết vấn đề này bằng cách sử dụng mô-đun nhập hoặc lớp hoặc hàm khi cần. nếu chúng ta sử dụng phương pháp này, chúng ta có thể sửa chữa phụ thuộc vòng tròn

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

Tôi cũng gặp lỗi này, vì một lý do khác ...

from my_sub_module import my_function

Kịch bản chính có kết thúc dòng Windows. my_sub_moduleđã kết thúc dòng UNIX. Thay đổi chúng để được cùng một vấn đề cố định. Họ cũng cần phải có mã hóa ký tự tương tự.


7

Như đã đề cập, điều này được gây ra bởi một phụ thuộc tròn . Điều chưa được đề cập là khi bạn đang sử dụng mô-đun Python và bạn chỉ nhập một lớp để chú thích các loại , bạn có thể sử dụng các tham chiếu chuyển tiếp :

Khi một gợi ý kiểu chứa các tên chưa được xác định, định nghĩa đó có thể được biểu thị dưới dạng một chuỗi ký tự, sẽ được giải quyết sau.

và loại bỏ sự phụ thuộc ( nhập khẩu ), ví dụ thay vì

from my_module import Tree

def func(arg: Tree):
    # code

làm:

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

(lưu ý importtuyên bố đã xóa )


6

Không đặt tên tập lệnh python hiện tại của bạn bằng tên của một số mô-đun khác mà bạn nhập

Giải pháp: đổi tên tập lệnh python đang hoạt động của bạn

Thí dụ:

  1. bạn đang làm việc trong medicaltorch.py
  2. trong tập lệnh đó, bạn có: from medicaltorch import datasets as mt_datasetsnơi medicaltorchđược cho là một mô-đun đã cài đặt

Điều này sẽ thất bại với ImportError. Chỉ cần đổi tên tập lệnh python làm việc của bạn trong 1.


Cảm ơn, điều này giải quyết vấn đề mà tôi đã có. Tôi đã sử dụng thư viện colorama và đặt tên tệp colorama.py, vì vậy python không biết nhập gì. Thay đổi tên tập tin giúp.
Marek Bodziony

5

Đừng nhìn thấy cái này ở đây - điều này cực kỳ ngu ngốc, nhưng hãy đảm bảo bạn đang nhập đúng biến / hàm.

Tôi đã nhận được lỗi này

ImportError: không thể nhập tên IMPLICIT_WAIT

vì biến của tôi đã thực sự IMPLICIT_TIMEOUT.

Khi tôi thay đổi nhập khẩu để sử dụng tên chính xác, tôi không còn gặp lỗi


1
Tôi đã sẵn sàng giết một ai đó đang cố gắng tìm ra lý do tại sao from PIL import Pillowkhông hoạt động. 😠
aalaap

5

Nếu bạn đang nhập file1.pytừ file2.pyvà sử dụng này:

if __name__ == '__main__':
    # etc

Các biến dưới đây file1.py không thể được nhập vào file2.py__name__ không bằng __main__ !

Nếu bạn muốn nhập một cái gì đó từ file1.pyđến file2.py, bạn cần sử dụng cái này trong file1.py:

if __name__ == 'file1':
    # etc

Trong trường hợp nghi ngờ, hãy đưa ra asserttuyên bố để xác định xem__name__=='__main__'


4

Một cách để theo dõi lỗi nhập là từng bước cố gắng chạy python trên mỗi tệp đã nhập để theo dõi lỗi xấu.

  1. bạn nhận được một cái gì đó như:

    python ./main.py

    ImportError: không thể nhập tên A

  2. sau đó bạn khởi chạy:

    python ./modules/a.py

    ImportError: không thể nhập tên B

  3. sau đó bạn khởi chạy:

    python ./modules/b.py

    ImportError: không thể nhập tên C (một số mô-đun NON-Hiện tại hoặc một số lỗi khác)


3

Cũng không trực tiếp liên quan đến OP, nhưng thất bại trong việc khởi động lại một PyCharm Python console, sau khi thêm một đối tượng mới cho một mô-đun, cũng là một cách tuyệt vời để có được một rất khó hiểuImportError: Cannot import name ...

Điều khó hiểu là PyCharm sẽ tự động hoàn tất quá trình nhập trong bảng điều khiển, nhưng quá trình nhập không thành công.


2

Vấn đề rất rõ ràng: sự phụ thuộc vòng tròn giữa tên trong entityphysicsmô-đun.

Bất kể nhập toàn bộ mô-đun hoặc chỉ một lớp, tên phải được tải.

Xem ví dụ này:

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

Điều này sẽ được tổng hợp thành:

# 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!

Với một thay đổi nhỏ, chúng ta có thể giải quyết điều này:

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

Điều này sẽ được tổng hợp thành:

# 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

Trong trường hợp của tôi, tôi đã làm việc trong một sổ ghi chép Jupyter và điều này đã xảy ra do quá trình nhập đã được lưu vào bộ nhớ cache từ khi tôi đã xác định lớp / hàm trong tệp làm việc của mình.

Tôi khởi động lại kernel Jupyter của tôi và lỗi biến mất.


1

Không dành riêng cho người hỏi này, nhưng lỗi tương tự này sẽ hiển thị nếu tên lớp trong quá trình nhập của bạn không khớp với định nghĩa trong tệp bạn đang nhập.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.