Комментарии 10
Как часто применяются эти типы оптимизации? Или все чаще используется numpy, pandas и другие инструменты ds?
В идеале всегда замечать)
Генераторы экономят память и позволяют закончить вычисления на промежуточном этапе. Полезны даже когда можно использовать векторизацию.
map и списковые выражения, работают быстрее циклов и часто легче читаются. Я стараюсь их использовать вместов циклов (for, while). Но больше из-за чиатемость, чем производительности.
Пример с append выроженный. Если данных мало, то пофиг, а если много, то стоит подключить numpy.
С глобальными переменнами не эксперементировал. Хотя я бы упростил пример, там дело в том, что переменную ищут сначала в локальном словаре, а потом в словаре выше. Так что с любой константой скорее всего воспроизводится. C появление JIT, скорее всего станет не актуально.
Использование
append
внутри цикла может замедлить выполнение функции, потому что Python каждый раз создает новый список.
Учите матчасть. Не каждый.
Вот хорошо написано, и полезно, но почему хоть какие-то замеры приведены только для первого пункта? Интересно было бы узнать, насколько сотня-другая for-ов выполнится быстрее while-ов и т.д.
Не, можно конечно и самостоятельно поэкспериментировать, но автор статьи мог бы избавить читателей от этого.
Сотня другая итераций циклов, будет сильно ниже погрешности измерений. Тут миллионы нужны.
Ну и в разных версиях Питона будут сильно разные цифры.
Ну или миллионы. Версию взять самую последнюю, думаю это имеет смысл.
Просто хочется видеть, насколько велика разница, ну как минимум проценты или доли процента, есть ли смысл вообще заморачиваться такими оптимизациями.
Вот, например, ради интереса для циклов
Скрытый текст
from time import perf_counter
def count_time(fun):
start = perf_counter()
fun()
end = perf_counter()
print(end - start)
def fun_for():
for i in range(10000):
_ = i + i
for j in range(2000):
_ = i + j
def fun_while():
i = 0
while i < 10000:
_ = i + i
j = 0
i += 1
while j < 2000:
_ = i + j
j += 1
count_time(fun_for)
count_time(fun_while)
Получилось:
2.5038714 для for
3.6994507 для while
Разница ощутимая
Использование map и filter
Сам Гвидо когда-то писал что лучше использовать list comprehension вместо map, т.к. производительность выше (источник – http://python-history.blogspot.com/2010/06/from-list-comprehensions-to-generator.html). Да и в принципе сейчас легко гуглится что list comprehension заменяет и map, и filter в одном
Да, map / filter возвращают не массив, а генератор, но в контексте, который представлен в статье, берётся list от этого генератора, и смысл пропадает. При этом есть возможность таким же образом создать и генератор (Py 3.11):
a = [1, 2, 3, 4]
a_map_list = [x*x for x in a] # вернёт [1, 4, 9, 16]
a_map_gen = (x*x for x in a) # вернёт generator, который при итерации выдаст те же значения, что и при итерации по `a_map_list`
Избегайте append в циклах
Вот тест timeit. Результаты теста о советах подобного типа говорят сами за себя.
# python3.10 -m timeit 'result = []' 'for i in range(10):' ' result.append(i)'
500000 loops, best of 5: 676 nsec per loop
# python3.10 -m timeit 'result = [0] * 10' 'for i in range(10):' ' result[i] = i'
500000 loops, best of 5: 545 nsec per loop
# python3.12 -m timeit 'result = []' 'for i in range(10):' ' result.append(i)'
1000000 loops, best of 5: 352 nsec per loop
# python3.12 -m timeit 'result = [0] * 10' 'for i in range(10):' ' result[i] = i'
1000000 loops, best of 5: 354 nsec per loop
Использование map и filter
Вот прям очень говорящий пример, почему статья в минусах:
# python3.10 -m timeit -s 'numbers = [1, 2, 3, 4]' 'list(filter(lambda x: x % 2 == 0, numbers))'
500000 loops, best of 5: 616 nsec per loop
# python3.10 -m timeit -s 'numbers = [1, 2, 3, 4]' '[x for x in numbers if x % 2 == 0]'
1000000 loops, best of 5: 365 nsec per loop
# python3.12 -m timeit -s 'numbers = [1, 2, 3, 4]' 'list(filter(lambda x: x % 2 == 0, numbers))'
500000 loops, best of 5: 598 nsec per loop
# python3.12 -m timeit -s 'numbers = [1, 2, 3, 4]' '[x for x in numbers if x % 2 == 0]'
1000000 loops, best of 5: 200 nsec per loop
5 способов оптимизации функций в Python