2012-05-10 34 views
87

Trong khi profiling một đoạn mã python (python 2.6 lên đến 3.2), tôi phát hiện ra rằng str phương pháp để chuyển đổi một đối tượng (trong trường hợp của tôi một số nguyên) thành một chuỗi gần như là một thứ tự cường độ chậm hơn so với sử dụng định dạng chuỗi.hiệu suất str trong python

Dưới đây là điểm chuẩn

>>> from timeit import Timer 
>>> Timer('str(100000)').timeit() 
0.3145311339386332 
>>> Timer('"%s"%100000').timeit() 
0.03803517023435887 

Có ai biết tại sao điều này là trường hợp? Tôi có thiếu gì đó không?

+2

Và điều gì về ''{}' định dạng (100000)' – wim

+0

Đó là chậm nhất nhưng cũng linh hoạt nhất. –

Trả lời

104

'%s' % 100000 được đánh giá bởi trình biên dịch và tương đương với một hằng số tại thời gian chạy.

>>> import dis 
>>> dis.dis(lambda: str(100000)) 
    8   0 LOAD_GLOBAL    0 (str) 
       3 LOAD_CONST    1 (100000) 
       6 CALL_FUNCTION   1 
       9 RETURN_VALUE   
>>> dis.dis(lambda: '%s' % 100000) 
    9   0 LOAD_CONST    3 ('100000') 
       3 RETURN_VALUE   

% với một biểu thời gian chạy không phải là (đáng kể) nhanh hơn str:

>>> Timer('str(x)', 'x=100').timeit() 
0.25641703605651855 
>>> Timer('"%s" % x', 'x=100').timeit() 
0.2169809341430664 

Do lưu ý rằng str vẫn còn hơi chậm, như @DietrichEpp nói, đây là bởi vì str liên quan đến tra cứu và các hoạt động gọi hàm, trong khi % biên dịch thành một mã bytecode ngay lập tức:

>>> dis.dis(lambda x: str(x)) 
    9   0 LOAD_GLOBAL    0 (str) 
       3 LOAD_FAST    0 (x) 
       6 CALL_FUNCTION   1 
       9 RETURN_VALUE   
>>> dis.dis(lambda x: '%s' % x) 
10   0 LOAD_CONST    1 ('%s') 
       3 LOAD_FAST    0 (x) 
       6 BINARY_MODULO  
       7 RETURN_VALUE   

Tất nhiên ở trên là đúng cho hệ thống tôi đã thử nghiệm trên (CPython 2.7); các triển khai khác có thể khác nhau.

+0

Thực tế điều này có vẻ như lý do, tôi chỉ cố gắng bản thân mình và định dạng chuỗi chỉ là khoảng 5% nhanh hơn 'str'. Cảm ơn về câu trả lời. Không có lý do để thay đổi mã ở khắp mọi nơi :-) –

+2

Để xây dựng thêm: 'str' là tên có thể được phục hồi cho một thứ khác ngoài kiểu chuỗi, nhưng định dạng chuỗi - tức là phương thức' str .__ mod__' - không thể thay thế, cho phép trình biên dịch thực hiện tối ưu hóa. Trình biên dịch không làm được gì nhiều trong cách tối ưu hóa, nhưng nó có nhiều hơn bạn có thể nghĩ :) –

+4

... và bài học để tìm hiểu ở đây là: không bao giờ sử dụng chữ trong các bài kiểm tra như thế này! – UncleZeiv

14

Một lý do đáng lưu ý là thực tế là str(100000) liên quan đến tra cứu toàn cầu, nhưng "%s"%100000 thì không. Các str toàn cầu đã được nhìn lên trong phạm vi toàn cầu. Điều này không chiếm toàn bộ chênh lệch:

>>> Timer('str(100000)').timeit() 
0.2941889762878418 
>>> Timer('x(100000)', 'x=str').timeit() 
0.24904918670654297 

Theo ghi nhận của thg435,

>>> Timer('"%s"%100000',).timeit() 
0.034214019775390625 
>>> Timer('"%s"%x','x=100000').timeit() 
0.2940788269042969