2012-07-28 25 views
33

Tôi có một mô-đun Chai webserver với dòng sau:Hai mô-đun Python yêu cầu nội dung của nhau - có thể hoạt động được không?

from foobar.formtools import auto_process_form_insert 

foobar.formtools mô-đun chứa dòng này:

from foobar.webserver import redirect, redirect_back 

Tất nhiên, cả hai kết quả trong các lỗi sau đây (theo thứ tự):

ImportError: cannot import name auto_process_form_insert
ImportError: cannot import name redirect

Chỉ đơn giản là một thực tế là trong Python hai mô-đun không thể nhập lẫn nhau và tất cả các mô-đun nhập khẩu phải được phân cấp al trong tự nhiên, hoặc tôi đang làm điều gì đó sai? Ngoài ra, có một cách giải quyết ngắn gọn để đặt tất cả các chức năng tốt đẹp này trong các mô-đun mới không?

+3

Như đã giải thích trong câu trả lời của tôi, có thể cho các mô-đun nhập vào nhau, nhưng nếu bạn cần làm điều đó, bạn có thể muốn xem xét lại thiết kế của mình. – icktoofay

+0

Tôi nghĩ rằng giải thích này dễ hiểu hơn nhiều: http://stackoverflow.com/questions/9642451/python-files-import-from-each-other – rizkiaditya24

Trả lời

42

Mô-đun có thể nhập lẫn nhau theo chu kỳ, nhưng có sự bắt giữ. Trong trường hợp đơn giản, nó sẽ hoạt động bằng cách di chuyển các câu lệnh import vào cuối tệp hoặc không sử dụng cú pháp from.

Dưới đây là lý do tại sao mà làm việc:

Khi bạn nhập một mô-đun, Python đầu tiên kiểm tra sys.modules. Nếu nó ở trong đó, nó chỉ cần nhập từ đó. Nếu nó không có ở đó, nó sẽ cố gắng nhập nó theo cách thông thường; về cơ bản, nó tìm thấy các tập tin và chạy các công cụ trong đó.

Chạy mô-đun sẽ điền nội dung của mô-đun. Ví dụ: giả sử chúng tôi có mô-đun này, được đặt tên sáng tạo example_opener:

import webbrowser 

def open_example(): 
    webbrowser.open('http://www.example.com/') 

Khi bắt đầu, mô-đun trống. Sau đó, Python thực thi:

import webbrowser 

Sau đó, mô-đun chỉ chứa webbrowser. Sau đó, Python thực hiện điều này:

def open_example(): 
    webbrowser.open('http://www.example.com/') 

Python tạo open_example. Bây giờ, mô-đun chứa webbrowseropen_example.

Say webbrowser chứa mã này:

from example_opener import open_example 

def open(url): 
    print url 

Say example_opener được nhập khẩu đầu tiên. Mã này được thực hiện:

import webbrowser 

webbrowser vẫn chưa được nhập khẩu, vì vậy Python thực hiện các nội dung của webbrowser:

from example_opener import open_example 

example_openerđã được nhập khẩu, nhưng chưa được thực hiện đầy đủ. Python không quan tâm. Python kéo mô-đun ra khỏi sys.modules. Tại thời điểm này, example_opener vẫn còn trống. Chưa xác định được open_example, và thậm chí không hoàn tất nhập webbrowser. Python không thể tìm thấy open_example trong example_opener, do đó không thành công.

Điều gì sẽ xảy ra nếu chúng tôi nhập open_example từ cuối webbrowserwebbrowser từ cuối example_opener? Python sẽ bắt đầu bằng cách thực hiện mã này:

def open_example(): 
    webbrowser.open('http://www.example.com/') 

webbrowser chưa hề tồn tại, nhưng nó không quan trọng cho đến khi open_example được gọi. Bây giờ example_opener chỉ chứa open_example. Sau đó nó thực thi:

import webbrowser 

Nó chưa được nhập, vì vậy Python thực hiện webbrowser. Nó bắt đầu:

def open(url): 
    print url 

Nó định nghĩa open. Sau đó, nó thực hiện:

from example_opener import open_example 

example_opener là trong sys.modules, vì vậy nó sử dụng đó. example_opener chứa open_example, vì vậy nó thành công. Python kết thúc nhập webbrowser. Điều đó kết thúc nhập webbrowser từ example_opener. Đó là điều cuối cùng trong example_opener, vì vậy việc nhập example_opener hoàn tất, cũng thành công.

+0

Phân tích chi tiết. Đây thường là những gì tôi phải làm trong django, nơi đôi khi bạn chỉ cần nhập khẩu tròn. Nhập ở dưới cùng hoặc trong phạm vi hàm hoặc phương thức. – jdi

+0

Đã thêm đoạn văn ở dưới cùng và đánh dấu chính xác – Hubro

+0

@Codemonkey: Tôi nhận thấy bạn đã thêm rằng bạn có thể tránh sử dụng cú pháp 'từ ... nhập ...' nhưng tôi đã có câu trả lời ở trên cùng: " Trong trường hợp đơn giản, nó sẽ hoạt động bằng [...] không sử dụng cú pháp 'from'." – icktoofay

12

Đừng làm from ... import .... Chỉ cần thực hiện import ... và tham chiếu các đối tượng của nó bằng tên mô-đun.

+0

Tôi không nghĩ rằng sẽ giải quyết một vấn đề nhập khẩu thông tư mặc dù? – jdi

+4

@jdi: Nó sẽ. Tại thời điểm nhập khẩu, mô-đun sẽ trống, nhưng vì nó không cố gắng để có được bất cứ điều gì bên trong của nó (chưa), nó không quan trọng. – icktoofay

+0

Ah, đúng vậy. Đó là một cách tiếp cận thay vì nhập khẩu trực tiếp ở phía dưới – jdi

Các vấn đề liên quan