2012-01-27 4 views
6

Khi nghi ngờ, tôi thường đặt các câu lệnh nhập của mình ở đầu mô-đun. Thông thường, điều này sẽ giảm bớt sự lặp lại, điều này rất hay. Tuy nhiên, có một nhược điểm hiệu suất trong trường hợp chỉ có một hàm duy nhất (hoặc lớp) yêu cầu nhập khẩu?Nhập bằng Python ở mức chức năng VS. Cấp mô-đun

thực hiện những điều sau đây chỉ nhập khi chức năng được gọi?

 def func(): 
     from task import test 

Nếu vậy, tôi hình dung rằng có thể có hiệu quả nhỏ. Tôi cũng giả định rằng bạn có thể nhận được một số điểm bổ sung để thu thập rác nhanh hơn và phạm vi biến đổi, vì các đối tượng đã nhập sẽ không được thêm vào từ điển chung. Là một người đăng khác độc đáo đặt nó:

Điều này chủ yếu là do tra cứu biến. Tìm kiếm một biến trong phạm vi toàn cầu yêu cầu tra cứu từ điển. Ngược lại, trình biên dịch xác định tên địa phương tĩnh và tham chiếu chúng theo chỉ mục, do đó không cần tra cứu từ điển.

Có phải những giả định công bằng đó là tôi hoàn toàn không có cơ sở?

Cảm ơn

+2

Đối với hiệu suất tra cứu tên: ** Nó không quan trọng. ** Trong trường hợp hiếm hoi, bạn sẽ tìm ra khi bạn đã hoàn thành mã, phát hiện ra nó quá chậm và được lược tả. – delnan

Trả lời

4

Nhập bằng chức năng chỉ được nhập khi chức năng chạy. Hãy nhớ rằng trong Python, tất cả các câu lệnh được thực hiện khi chúng gặp phải, và việc nhập khẩu là các câu lệnh giống như bất cứ điều gì khác. Nhập khẩu cấp cao nhất được nhập khi mô-đun được nhập, vì chúng là các câu lệnh cấp cao nhất trong mô-đun.

Mối quan tâm của bạn về tra cứu tên được hiểu sai: sự khác biệt là không đáng kể và chỉ nên được xem xét nếu tiểu sử hiển thị sự cố.

Tôi chỉ nhập mô-đun vào phạm vi chức năng vì hai lý do: 1) để khắc phục các vấn đề nhập vòng tròn, có thể giải quyết btw theo cách khác bằng cách tái cấu trúc hoặc 2) nếu mô-đun là tùy chọn và chức năng không được nhiều người dùng của tôi sử dụng. Trong trường hợp 2), mô-đun có thể bị mất hoàn toàn và sẽ không có vấn đề gì trừ khi ai đó gọi hàm này.

+0

Đây là một câu hỏi lý thuyết. Dường như có sự khác biệt, ngay cả khi có thể cẩu thả. Cảm ơn Ned – Ben

+0

Đó có phải là cách nhiệt tình nhất? Tôi thấy một số người thực hiện nhập khẩu tại __init__.py tại thư mục gốc của mô đun của họ và nhập mọi thứ từ đó. Điều đó có thể được sử dụng để giải quyết một số thông tư nhập khẩu? – radtek

3

Hãy nhìn vào những gì các bytecode sẽ trông như thế cho hai chức năng sau:

def func1(): 
    """ test imported each time function is run """ 
    from task import test 
    test() 

def func2(): 
    """ test was imported at top of module """ 
    test() 

Như bạn thấy dưới đây, func2() tiết kiệm rất nhiều bước bằng nhập khẩu toàn cầu test chức năng .

>>> dis.dis(func1) 
    3   0 LOAD_CONST    1 (-1) 
       3 LOAD_CONST    2 (('test',)) 
       6 IMPORT_NAME    0 (task) 
       9 IMPORT_FROM    1 (test) 
      12 STORE_FAST    0 (test) 
      15 POP_TOP 

    4   16 LOAD_FAST    0 (test) 
      19 CALL_FUNCTION   0 
      22 POP_TOP 
      23 LOAD_CONST    3 (None) 
      26 RETURN_VALUE 
>>> dis.dis(func2) 
    3   0 LOAD_GLOBAL    0 (test) 
       3 CALL_FUNCTION   0 
       6 POP_TOP 
       7 LOAD_CONST    1 (None) 
      10 RETURN_VALUE 

Việc tính toán này có thể được tối ưu hóa sớm, như đã nêu trong nhận xét của Delnan.

Đối với test nằm trong không gian tên chung, điều đó không có khả năng gây ra bất kỳ vấn đề về hiệu suất tra cứu nào. Cách đáng chú ý nhất tôi nghĩ rằng bạn có thể thấy điều này là nếu có một va chạm băm cho test và một tên khác mà bạn sử dụng rất thường xuyên, điều này khiến cho việc tra cứu tên thứ hai đó mất nhiều thời gian hơn. Một lần nữa, tối ưu hóa sớm để xem xét trường hợp hiếm hoi lên phía trước.

+1

Nhưng lưu ý rằng nó sẽ không thực sự nhập các mô-đun nhiều hơn một lần - nó chỉ kiểm tra xem có phải mỗi lần nó được gọi. – delnan

+0

Cảm ơn bạn đã đặt nó ra như thế này; nó rất hữu ích. Không quen thuộc với thư viện dis. – Ben

0

Tôi nghĩ có ý nghĩa khi đặt nhập trong định nghĩa nếu nó sẽ không được gọi rất thường xuyên.