Комментарии 16
Не знаю питон, но сомневаюсь, что там для проверки числа нужно генерировать массив на миллион элементов. Почему больше-меньше не используется?
Тут в целом больше вопросов, чем ответов. Называем статью "Эффективное использование any и all в Python" и говорим, что выделить память на весь список дороже, чем создать генератор. Ну такое
Согласен, авторы просто усложняют жизнь, потому что больше-меньше работает вполне достойно:
ch = 200000000
if ch >= 1 and ch <= 1000000000:
print(True)
else:
print(False)
При этом, код выполняется менее, чем за 1 секунду...
Почему больше-меньше не используется?
Возможно, это "игрушечный пример" просто. Типа, у нас есть большой пребольшой массив, и в нем надо что-то искать. И автор не стал заморачиваться, просто сгенерировал его из чисел от 1 до много.
def find_200_million():
return True
Не знаю Питона, но вообще эти списковые включения выглядят весьма интересно.
В каких языках они еще есть?
Является ли само по себе выражение "спискового включения" объектом, или оно сразу "раскрывается" в список (запускается на генерацию)? (здесь я имею в виду аналогию с лямбда-функцией в большинстве языков: само по себе лямбда-выражение - это не вызов функции, а специальный объект, который можно сохранить в переменной; вызов функции происходит только при применении операции вызова "()" )
Еще приходит в голову аналогия с диапазонными объектами, которые тоже есть в некоторых языках. Выражения вида "10..20" можно интерпретировать как специальные объекты, хранящие два числа, а можно - как полноценные списки всех чисел в заданном диапазоне.
Не создавайте списки для однопроходных алгоритмов, для этого есть генераторы
Весь смысл статьи. Это ещё и перевод. Не, ну понятно, корпоративный блог кушает деньги, нужно в него что-то писать.
Всегда опасаюсь, что кто-то через поиск найдет по тексту задачи подобную информацию и перенесет в проект решение не глядя...
Про операции сравнения уже написали выше в комментариях, поэтому вот еще один способ решения задачи, более близкий к исходному варианту + сравнение с функцией из статьи:
def foo() -> bool:
return 200_000_000 in (range(1_000_000_000))
from dis import dis
dis(foo)
2 0 LOAD_CONST 1 (200000000)
2 LOAD_GLOBAL 0 (range)
4 LOAD_CONST 2 (1000000000)
6 CALL_FUNCTION 1
8 COMPARE_OP 6 (in)
10 RETURN_VALUE
def find_200_million() -> bool:
return any(True for number in range(1_000_000_000) if number == 200_000_000)
dis(find_200_million)
2 0 LOAD_GLOBAL 0 (any)
2 LOAD_CONST 1 (<code object <genexpr> at 0x7f3d31d61930, file "<stdin>", line 2>)
4 LOAD_CONST 2 ('find_200_million.<locals>.<genexpr>')
6 MAKE_FUNCTION 0
8 LOAD_GLOBAL 1 (range)
10 LOAD_CONST 3 (1000000000)
12 CALL_FUNCTION 1
14 GET_ITER
16 CALL_FUNCTION 1
18 CALL_FUNCTION 1
20 RETURN_VALUE
Позволю себе развернуть мысль: если нужно проверить, входит ли элемент в последовательность, — просто используйте синтаксис
x in y
Интерпретатор сам все сделает наилучшим образом: для перечисления или словаря достанет значение по ключу, для списка линейно переберет элементы до первого совпадения и вернет True.
Проверка на вхождение числа в диапазон (или, в общем случае, арифметическую прогрессию), представленный объектом range, выполняется за единицы микросекунд и не зависит от величины числа или диапазона.
>>> from timeit import timeit
>>> timeit('200_000_000 in range(1_000_000_000)', number=1)
2.7045607566833496e-06
Показатели неполные! Для корректности нужно смотреть также и на наихудший результат, т.к. для поиска последнего элемента в каком то варианте кода может понадобиться неожиданно больше времени чем в другом варианте кода. Я решил перепроверить.
Ищем значение 200000000
any([number == 200000000 for number in range(1_000_000_000)])
0:00:45.137719
any([True for number in range(1_000_000_000) if number == 200000000])
0:00:35.904143
any(True for number in range(1_000_000_000) if number == 200000000)
0:00:07.327660
any(number == 200000000 for number in range(1_000_000_000))
0:00:10.658496
all(False for number in range(1_000_000_000) if number == 200000000)
0:00:07.024172
Далее решил проверить поиск числа 1.
Ищем значение 1
any([number == 1 for number in range(1_000_000_000)])
0:00:44.296145
any([True for number in range(1_000_000_000) if number == 1])
0:00:37.544449
any(True for number in range(1_000_000_000) if number == 1)
0:00:00.000023
any(number == 1 for number in range(1_000_000_000))
0:00:00.000003
all(False for number in range(1_000_000_000) if number == 1)
0:00:00.000003
Ну и конечно же худший вариант, число 999999999.
Ищем значение 999999999
any([number == 999999999 for number in range(1_000_000_000)])
0:00:50.238195
any([True for number in range(1_000_000_000) if number == 999999999])
0:00:37.451774
any(True for number in range(1_000_000_000) if number == 999999999)
0:00:36.485738
any(number == 999999999 for number in range(1_000_000_000))
0:00:49.075029
all(False for number in range(1_000_000_000) if number == 999999999)
0:00:36.864547
Как видно, результат не такой уж и радостный, но в некоторых случаях лучше чем изначальный вариант :)
В первом слове заголовка потерялась приставка 'не'.
Эффективное использование any и all в Python