2010-06-22 28 views
104

Ưu điểm và nhược điểm của việc nhập một mô-đun Python và/hoặc chức năng bên trong một hàm, liên quan đến hiệu quả của tốc độ và bộ nhớ là gì?Trong Python, điều gì xảy ra khi bạn nhập vào bên trong một hàm?

Tính năng này có nhập lại mỗi khi chức năng được chạy hay có lẽ chỉ một lần khi bắt đầu có hay không chức năng được chạy?

+3

Không có lợi ích về tốc độ (gọi 'nhập' rất tốn kém, ngay cả khi mô-đun đã được tải). Nếu bạn muốn một lợi ích tốc độ, nó nhanh hơn (nếu bạn truy cập vào mô-đun ít nhất 4-5 lần) để chỉ định mô-đun cho biến cục bộ làm điều đầu tiên bạn làm trong hàm của mình và sau đó truy cập nó thông qua biến cục bộ đó (vì tra cứu biến cục bộ rất nhanh). –

+3

(Tua nhanh tới 26:30 trong video tại http://us.pycon.org/2010/conference/schedule/event/71/ nếu bạn muốn một ví dụ thú vị về cách nhập sai một cách vô lý trong một hàm có thể) –

+0

@Nick: Khi nghe điều này, có vẻ như việc nhập nhiều lần liên tục chậm vì mỗi lần bạn thử và kiểm tra xem nó có được nhập hay không. Bạn đang nói rằng bên ngoài của chức năng nhập khẩu nó và đặt nó như là một biến toàn cầu và lấy biến toàn cầu bên trong chức năng? –

Trả lời

89

Tái nhập có được nhập lại mỗi khi chức năng được chạy không?

Không; hay đúng hơn, các mô-đun Python về cơ bản được lưu trong bộ nhớ cache mỗi khi chúng được nhập, do đó việc nhập thời gian thứ hai (hoặc thứ ba, thứ tư ...) không thực sự buộc chúng phải trải qua toàn bộ quá trình nhập một lần nữa.

Nó có nhập một lần vào lúc bắt đầu cho dù chức năng có được chạy không?

Không, chỉ được nhập khi và khi chức năng được thực hiện.

Đối với những lợi ích: điều đó phụ thuộc, tôi đoán vậy. Nếu bạn chỉ có thể chạy một hàm rất hiếm khi và không cần mô-đun được nhập bất kỳ nơi nào khác, thì có thể có lợi khi chỉ nhập mô-đun vào hàm đó. Hoặc nếu có xung đột tên hoặc lý do khác bạn không muốn mô-đun hoặc biểu tượng từ mô-đun có sẵn ở mọi nơi, bạn chỉ có thể nhập mô-đun đó trong một chức năng cụ thể. (Tất nhiên, luôn có from my_module import my_function as f cho những trường hợp đó.)

Nói chung, có thể không có lợi. Trong thực tế, hầu hết các hướng dẫn kiểu Python khuyến khích các lập trình viên đặt tất cả các hàng nhập vào đầu tệp mô-đun.

+6

Trong cùng một dòng suy nghĩ, điều này có thể làm cho một depedency tùy chọn nếu nhập khẩu được giấu bên trong một chức năng phụ trợ. –

+1

Tôi sử dụng nó cho các phụ thuộc tùy chọn khi tôi viết các mô-đun thư viện cho chính mình. Tôi làm cho mỗi hàm bên trong một mô-đun thư viện phụ thuộc vào số lượng nhập tối thiểu. – CodeMonkey

9

Nó nhập một lần khi hàm thực hiện lần đầu tiên.

Ưu điểm:

  • nhập khẩu liên quan đến các chức năng mà họ đang sử dụng trong
  • dễ dàng di chuyển chức năng xung quanh gói

Nhược điểm:

  • không thể nhìn thấy mô-đun nào mô-đun này có thể phụ thuộc vào
+0

nếu bạn làm điều gì đó như 'grep import/path/to/module' nó sẽ hiển thị cho bạn tất cả các mô-đun mà nó nhập. – dashaxiong

2

Nó nhập một lần khi chức năng được gọi lần đầu tiên.

Tôi có thể tưởng tượng thực hiện theo cách này nếu tôi có chức năng trong mô-đun đã nhập được sử dụng rất ít khi và là người duy nhất yêu cầu nhập. Có vẻ khá xa vời, mặc dù ...

5

Nhập bên trong một hàm sẽ nhập mô-đun hiệu quả một lần .. lần đầu tiên chức năng được chạy.

Bạn phải nhập nhanh như vậy dù bạn nhập nó ở trên cùng hay khi chức năng được chạy. Đây không phải là một lý do tốt để nhập khẩu trong một def. Ưu điểm? Nó sẽ không được nhập nếu chức năng không được gọi .. Đây thực sự là một lý do hợp lý nếu mô-đun của bạn chỉ yêu cầu người dùng phải có một mô-đun nhất định được cài đặt nếu họ sử dụng các chức năng cụ thể của bạn ...

Nếu đó là anh ta không lý do bạn làm điều này, nó gần như chắc chắn là một ý tưởng tồi tệ.

32

Lần đầu tiên bạn import goo từ mọi nơi (bên trong hoặc bên ngoài một chức năng), goo.py (hoặc biểu mẫu có thể nhập khác) được tải và sys.modules['goo'] được đặt thành đối tượng mô đun do đó được tạo. Bất kỳ nhập khẩu trong tương lai trong cùng một hoạt động của chương trình (một lần nữa, cho dù bên trong hoặc bên ngoài một chức năng) chỉ cần tra cứu sys.modules['goo'] và ràng buộc nó vào tên mã goo trong phạm vi thích hợp. Việc tra cứu dict và ràng buộc tên là các hoạt động rất nhanh.

Giả sử đầu tiên import được hoàn toàn khấu hao theo thời gian của chương trình dù sao, có "phạm vi thích hợp" được mô-đun cấp có nghĩa là mỗi lần sử dụng của goo.this, goo.that, vv, là hai tra cứu dict - một cho goo và một cho tên thuộc tính. Có "mức chức năng" trả thêm một cài đặt biến cục bộ cho mỗi lần chạy hàm (thậm chí nhanh hơn phần tra cứu từ điển!), Nhưng tiết kiệm một lần tra cứu dict (trao đổi nó cho tra cứu biến cục bộ, nhanh chóng) cho mỗi goo.this (vv) truy cập, về cơ bản giảm một nửa thời gian tra cứu như vậy.

Chúng ta đang nói về một vài nano giây theo cách này hay cách khác, vì vậy nó hầu như không phải là một tối ưu hóa đáng giá. Một lợi thế đáng kể có khả năng là có import trong một hàm là khi chức năng đó có thể không cần thiết trong một chương trình cụ thể, ví dụ, hàm đó xử lý lỗi, dị thường và các tình huống hiếm gặp nói chung; nếu trường hợp đó xảy ra, bất kỳ lần chạy nào không cần chức năng sẽ không thực hiện việc nhập (và đó là tiết kiệm micro giây, không chỉ là nano giây), chỉ chạy mà không cần chức năng sẽ trả giá (khiêm tốn nhưng có thể đo lường).

Nó vẫn là một tối ưu hóa chỉ đáng giá trong các tình huống khá khắc nghiệt, và có rất nhiều người khác tôi sẽ xem xét trước khi cố gắng để ép ra micro giây theo cách này.

+0

Tối ưu hóa này thực sự không bao giờ đáng giá - không có số lượng truy cập biến cục bộ nhanh sẽ bù đắp cho chi phí đáng kinh ngạc khi gọi 'import', ngay cả khi mô-đun đã được nạp. Kiểm tra xem liệu một mô-đun đã được tải là một hoạt động rất tốn kém (tương đối so với một số tra cứu từ điển toàn cầu). –

+2

Nhập mô-đun lần đầu tiên là tốn kém. Hãy thử chạy một tập lệnh trống so với một tập lệnh chứa 'chuỗi nhập, lặp, phân số, heapq, re, mảng, bisect, bộ sưu tập, toán học, os'. Việc đầu tiên mất trung bình 180 ms, và 230 ms thứ hai. Vì vậy, nó không phải là micro giây cho người mới bắt đầu. Đó là hàng chục mili giây (có thể truy cập đĩa xảy ra?). Điều này rất quan trọng đối với các tập lệnh nhỏ chạy nhiều lần (như phục vụ yêu cầu web). –

+0

@EvgeniSergeev Trong trường hợp đó bạn thường có một máy chủ chạy tất cả thời gian, do đó nó sẽ không tái nhập hơn và hơn nữa –

3

Tôi có thể đề xuất nói chung thay vì hỏi, "Liệu X có cải thiện hiệu suất của tôi không?" bạn sử dụng hồ sơ để xác định nơi chương trình của bạn là thực sự dành thời gian của nó và sau đó áp dụng tối ưu hóa theo nơi bạn sẽ nhận được nhiều lợi ích nhất?

Và sau đó bạn có thể sử dụng hồ sơ để đảm bảo rằng các tối ưu hóa của bạn đã thực sự mang lại lợi ích cho bạn.

+2

Tôi đồng ý với điều đó, đây là một câu hỏi tò mò hơn. Tôi đã tự hỏi phương thức nhập của Python hoạt động chi tiết hơn thế nào, nhiều hơn là cố gắng nâng cao hiệu suất sớm. Cảm ơn mặc dù :) –

+2

Ah. Vâng, tôi hy vọng rằng những câu trả lời tuyệt vời ở đây đã thỏa mãn sự tò mò của bạn! Effbot có một số thông tin có thể được sử dụng cho bạn: http://effbot.org/zone/import-confusion.htm Cuộn xuống "Có gì Python làm để nhập mô-đun?" – gomad

+0

Cảm ơn thông tin, câu trả lời rất tuyệt vời và hữu ích. –

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