Python: ведется ли в списках Python счет для len () или он считается для каждого вызова?

79

Если я продолжаю вызывать len () в очень длинном списке, я трачу время зря, или он сохраняет счетчик int в фоновом режиме?

PKKid
источник
Меня это всегда беспокоило. особенно когда мой профилировщик сказал мне, что я потратил 2,2 секунды программы, которая выполнялась в течение одной минуты, вызывая эту функцию.
Натан

Ответы:

87

Не волнуйтесь: конечно, это экономит счет и, таким образом, работа len()со списками довольно дешевая. Кстати, то же самое и со строками, словарями и наборами!

Фердинанд Бейер
источник
Я считаю, что он ведет счет, например, index of last item + 1 или что-то в этом роде, и вызывает значение len () из этого места в памяти. Я прав?
geekidharsh
13

Напишите свою программу так, чтобы она была оптимизирована для ясности и легко поддерживалась . Ваша программа понятнее с вызовом len(foo)? Тогда сделай это.

Вы беспокоитесь о затраченном времени? Используйте timeitмодуль в стандартной библиотеке, чтобы измерить затраченное время и посмотреть, имеет ли оно значение для вашего кода.

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

Помните, что , по словам Дональда Кнута , преждевременная оптимизация - это корень всех зол . Сосредоточьтесь только на скорости кода, скорость которого вы измерили , чтобы знать, окупится ли выгода затрат на изменение того, как он работает.

большой нос
источник
1
Я программист всего несколько месяцев в моей работе, и я поддерживаю оба метода. Таймер предлагает двухстрочную защиту от большого объема общепринятых мнений («ВЫБРАТЬ ... СЛУЧАЙНО слишком дорого»), которые будут брошены вам на пути.
Jesvin Jose 05
5

На вопрос был дан ответ ( lenO (1)), но вот как вы можете проверить это сами:

$ python -m timeit -s "l = range(10)" "len(l)"
10000000 loops, best of 3: 0.119 usec per loop
$ python -m timeit -s "l = range(1000000)" "len(l)"
10000000 loops, best of 3: 0.131 usec per loop

Да, не медленнее.

dF.
источник
3

«Список» Python - это действительно массив с изменяемым размером, а не связанный список, поэтому он где-то хранит размер.

Кен
источник
0

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

Георг Шёлли
источник
4
Будьте осторожны, это не обязательно верно для всех языков. Некоторые языки на самом деле используют связанный список и могут хранить или не хранить метаданные о размере. Прекрасным примером является Lisp, где списки используют относительно примитивные структуры из двух ячеек для построения самих себя, без метаданных. В этих случаях длительный вызов занимает O (n) времени.
Эштон К,