2015-07-21 3 views
0

Я хотел проверить, как работает сравнение строк (я хотел посмотреть, является ли это символом char, и если он проверяет длину строки перед сравнением), поэтому я использовал этот код :Непоследовательность сравнения строк в Python

s1 = 'abc' 
s2 = 'abcd' 
s3 = 'dbc' 
s4 = 'abd' 
t1 = time.clock() 
s1==s2 
print time.clock() - t1 
t2 = time.clock() 
s1==s3 
print time.clock() - t2 
t3 = time.clock() 
s1==s4 
print time.clock() - t3 

Когда я попробовал то же самое на очень длинных строк (~ 30MB текстовые файлы) он работал большой, и я узнал, что он выполняет проверку длины, а также сравнивает символ с помощью полукокса. Но когда я пробовал его на короткой строке (например, в коде выше), результаты производительности были очень непоследовательными. У любого есть идея, почему они были непоследовательными или что я сделал неправильно? (возможно, я ошибся, и сравнение не работает, как я думал?)

Редактировать: Пример для чего-то, что я также пробовал, это сравнить разные длины строки с определенной строкой. Я думал, что тот, который занимает больше всего времени, будет строкой с точной длиной другой, потому что остальные будут падать в проверке длины, но это также было непоследовательно). позволяет сказать, что строка, которую я проверяю, это «привет», поэтому я сравнил «a», «aa», «aaa» и т. Д. ... Я ожидал увидеть, что самая длинная проверка будет «aaaaa», но это было «а», и я понятия не имею, почему.

+2

«результаты были очень противоречивыми» - каким образом? Какой результат вы ожидали, и что вы видели? – TigerhawkT3

+0

@ TigerhawkT3 Я только что отредактировал сообщение, чтобы сделать его более понятным. – pystudent

+1

'time.clock' не является отличным выбором для сравнения скорости кода Python, особенно в современных многозадачных операционных системах, где потенциально десятки других процессов могут затормозить процессор за доли секунды, в то время как ваш скрипт выполняется в припадках и очередях. 'timeit' было бы лучше, так как это может усреднить периоды большой нагрузки, но все еще есть некоторая внутренняя неточность. – Kevin

ответ

1

Вы правы, что строки сравнивают длины перед сравнением содержимого (по крайней мере, в 2.7). Here является соответствующей частью string_richcompare:

if (op == Py_EQ) { 
    /* Supporting Py_NE here as well does not save 
     much time, since Py_NE is rarely used. */ 
    if (Py_SIZE(a) == Py_SIZE(b) 
     && (a->ob_sval[0] == b->ob_sval[0] 
     && memcmp(a->ob_sval, b->ob_sval, Py_SIZE(a)) == 0)) { 
     result = Py_True; 
    } else { 
     result = Py_False; 
    } 
    goto out; 
} 

Проще говоря, чеки, кажется, в порядке:

  • , если строки имеют один и тот же адрес памяти, то они равны. (не изображено в приведенном выше коде)
  • если строки имеют разный размер, они не равны.
  • если строки имеют другой первый символ, они не равны.
  • Если строки имеют одинаковые массивы символов, они равны.

Третья проверка не представляется абсолютно необходимой, но, вероятно, является оптимизацией, если вручную проверять содержимое массива быстрее, чем вызов memcmp.


Если бенчмаркинг предложил вам, что сравнение строк разной длины медленнее, чем сравнение строк одинаковой длины, это, вероятно, ложная тревога, вызванная не совсем надежным поведением clock, так как покрыты в других ответах и комментарии.

+0

Спасибо, что при объединении обоих ответов мне удалось выполнить проверку, которая работает как ожидалось. Большое спасибо вам обоим! – pystudent

2

Вы можете получить непоследовательные результаты при измерении очень малых времен. Вы получите лучший результат, повторяя эту операцию очень много раз, так что разница существенна:

t1 = time.clock() 
for i in range(10**6): 
    s1 == s2 
t2 = time.clock() 

еще лучше, использовать модуль timeit для обработки повторения (и других деталей как выключая вывоз мусора) для вас:

import timeit 

s1 = 'abc' 
s2 = 'abcd' 
s3 = 'dbc' 
s4 = 'abd' 
t1 = timeit.timeit('s1==s2', 'from __main__ import s1, s2', number=10**8) 
t2 = timeit.timeit('s1==s3', 'from __main__ import s1, s3', number=10**8) 
t3 = timeit.timeit('s1==s4', 'from __main__ import s1, s4', number=10**8) 
for t in (t1, t2, t3): 
    print(t) 

дает

2.82305312157 
2.83096408844 
3.15551590919 

Таким образом s1==s2 и s1==s3 принимают в основном такое же количество времени. s1==s4 требует немного больше времени, потому что больше символов нужно сравнивать до того, как равенство вернет False.


Кстати, в то время как time.clock используется timeit.default_timer для измерения времени на Windows, time.time используется timeit.default_timer для измерения времени на Unix. Используйте timeit.default_timer вместо time.clock или time.time , чтобы сделать ваш код более кросс-платформенным.

+0

Спасибо, когда вы комбинировали оба ответа, мне удалось выполнить проверку, которая работает должным образом. Большое спасибо вам обоим! – pystudent

Смежные вопросы