Làm thế nào để sử dụng python timeit khi truyền biến cho hàm?


76

Tôi đang vật lộn với việc sử dụng thời gian này và tự hỏi liệu có ai có mẹo nào không

Về cơ bản, tôi có một hàm (mà tôi chuyển một giá trị vào) mà tôi muốn kiểm tra tốc độ và tạo ra cái này:

if __name__=='__main__':
    from timeit import Timer
    t = Timer(superMegaIntenseFunction(10))
    print t.timeit(number=1)

nhưng khi tôi chạy nó, tôi gặp các lỗi kỳ lạ như đến từ mô-đun timeit.:

ValueError: stmt is neither a string nor callable

Nếu tôi chạy chức năng của riêng nó, nó hoạt động tốt. Khi tôi quấn nó trong mô-đun thời gian, tôi gặp lỗi (tôi đã thử sử dụng dấu ngoặc kép và không có..sameoutput).

Bât ki đê xuât nao đêu se tuyệt vơi!

Cảm ơn!

Câu trả lời:


128

Làm cho nó có thể gọi được:

if __name__=='__main__':
    from timeit import Timer
    t = Timer(lambda: superMegaIntenseFunction(10))
    print(t.timeit(number=1))

Nên làm việc


Điều đó đã hiệu quả! Cám ơn rất nhiều. Tôi cần tìm hiểu xem lambda làm gì..có vẻ như điều đó đã tạo ra sự khác biệt. Cảm ơn Pablo
Lostsoul.

6
giá như điều này có trong tài liệu ở đâu đó
endolith

17
Ồ nhưng lambda thêm một số chi phí, vì vậy không lý tưởng để thử nghiệm những thứ nhỏ. timeit 5*5là 33 ns trong khi timeit (lambda: 5*5)()là 233 ns.
endolith

Đây là hoàn hảo. Tôi gặp sự cố khi chỉ gọi timeitvới lambda (tập lệnh bị đóng băng; phương pháp tôi đang đo thời gian thực thi là retrbinaryđể tải xuống thông qua FTP bằng cách sử dụng ftplib). Một khi tôi sử dụng Timerđối tượng, nó đột nhiên hoạt động như một cái bùa. Không biết chuyện gì đã xảy ra ...: D
rbaleksandar

23

Timer(superMegaIntenseFunction(10))có nghĩa là "gọi superMegaIntenseFunction(10), sau đó chuyển kết quả cho Timer". Đó rõ ràng không phải là những gì bạn muốn. Timermong đợi một có thể gọi (giống như âm thanh của nó: một cái gì đó có thể được gọi, chẳng hạn như một hàm) hoặc một chuỗi (để nó có thể diễn giải nội dung của chuỗi dưới dạng mã Python). Timerhoạt động bằng cách gọi liên tục điều có thể gọi và xem lượng thời gian được sử dụng.

Timer(superMegaIntenseFunction)sẽ vượt qua kiểm tra loại, vì superMegaIntenseFunctioncó thể gọi được. Tuy nhiên, Timersẽ không biết những giá trị nào để chuyển sang superMegaIntenseFunction.

Tất nhiên, cách đơn giản để giải quyết vấn đề này là sử dụng một chuỗi với mã. Chúng ta cần chuyển đối số 'thiết lập' cho mã, bởi vì chuỗi được "hiểu là mã" trong ngữ cảnh mới - nó không có quyền truy cập giống globalsnhư vậy, vì vậy bạn cần chạy một đoạn mã khác để tạo định nghĩa có sẵn - xem câu trả lời của @ oxtopus.

Với lambda(như trong câu trả lời của @ Pablo), chúng ta có thể liên kết tham số 10với một lệnh gọi tới superMegaIntenseFunction. Tất cả những gì chúng tôi đang làm là tạo ra một chức năng, mà không có đối số, và các cuộc gọi superMegaIntenseFunctionvới 10. Nó giống như thể bạn đã sử dụng defđể tạo một hàm khác như vậy, ngoại trừ việc hàm mới không có tên (vì nó không cần tên).


18

Bạn nên chuyển một chuỗi. I E

t = Timer('superMegaIntenseFunction(10)','from __main__ import superMegaIntenseFunction')

Cảm ơn câu trả lời oxtopus! nó không hoạt động khi tôi đặt nó trong dấu ngoặc kép nên một chuỗi của nó, tôi gặp lỗi này: NameError: global name 'superMegaIntenseFunction' không được xác định. Bạn nghĩ tôi có thể thử gì nữa không?
Lostsoul

Đã sửa câu trả lời để bao gồm lập luận thiết lập. ( docs.python.org/library/timeit.html#timeit.Timer )
Austin Marshall

1

Một lưu ý cho những du khách trong tương lai. Nếu bạn cần làm cho nó hoạt động trong pdbtrình gỡ lỗi và superMegaIntenseFunctionkhông ở phạm vi toàn cầu, bạn có thể làm cho nó hoạt động bằng cách thêm vào globals:

globals()['superMegaIntenseFunction'] = superMegaIntenseFunction
timeit.timeit(lambda: superMegaIntenseFunction(x))

Lưu ý rằng chi phí thời gian lớn hơn một chút trong trường hợp này do các lệnh gọi hàm bổ sung. [nguồn]


0

Một cách để làm điều đó là sử dụng một phần để hàm, 'superMegaIntenseFunction' được sử dụng như một hàm có thể gọi (tức là không có ()) trong bộ đếm thời gian hoặc trực tiếp bên trong timeit.timeit. Sử dụng một phần sẽ truyền đối số cho hàm khi nó được gọi bởi bộ định thời.

from functools import partial
from timeit import timeit

print(timeit(partial(superMegaIntenseFunction, 10), number=1))
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.