70 subscribers
14 links
Советы от разработчика по языку программирования Python и его библиотекам.
Download Telegram
Channel created
Channel name was changed to «Python Tips»
Channel photo updated
Часто в литературе, сети Интернет и в коде реальных проектов можно встретить такое использование генераторных выражений:

total = sum([x for x in sequence])


Такой код хоть и правильный с точки зрения синтаксиса, тем не менее не является оптимальным. В большинстве случаев правильнее писать так:

total = sum(x for x in sequence)


Разница в том, что в первом случае в функцию sum передается список, созданный на основе генератора, а во втором — генератор. Для создания списка нужно выполнить дополнительные операции, а также выделить дополнительную память. При этом результат работы всего кода будет тот же самый.

Вывод: создавайте коллекции (кортежи, списки и т.п.) на основе генераторов только там, где это действительно нужно.

#python #оптимизация
Периодически на ревью вижу примерно такое использование функций all и any:

if any((
is_check1_passed(),
is_check2_passed(),
...
)):
pass


Скорее всего это делается для повышения читаемости кода, но это только моё предположение. С точки зрения логики программы это почти всегда рабочий код. Но вот с точки зрения оптимальности есть проблемы.

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

Более оптимальный код выглядит так:

if (
is_check1_passed() or
is_check2_passed() or
...
):
pass


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

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

Описание функций all и any: https://docs.python.org/3.6/library/functions.html#all

#python #оптимизация
В Python есть такие структуры данных, как кортежи (tuple) и списки (list). В книгах, статьях, в реальных проектах чаще встречается использование списков вместо кортежей там, где в этом нет необходимости:

gender = models.PositiveIntegerField(
'Пол',
choices=[GENDER_MALE, GENDER_FEMALE],
)


При хранении одних и тех же данных списки занимают больше места, чем кортежи. Например, на 64-хразрядной системе для хранения двух элементов в списке нужно 80 байт, а в кортеже — 64 (на 16 байт меньше). Для 1000 элементов отличие будет уже на 1064 байта. Это несущественно на небольших проектах, но становится актуальным для больших информационных систем, работающих с большим количеством данных, особенно в совокупности с другими способами оптимизации.

Совет: там, где нет потребности в изменении содержимого коллекции, используйте кортежи вместо списков.

#python #оптимизация
👍1
В отличие от кортежей и списков, множества (set, frozenset) и словари (dict) занимают больше места в памяти. Например, для множества из двух элементов понадобится 224 байта (кортеж — 64). Для 1000 элементов — 32992 и 8048 соответственно.

Однако у словарей и множеств есть важное преимущество: скорость поиска элемента в коллекции (оператор in). Если для кортежей и списков сложность данной операции равна O(n), то для множеств это O(1). Сравните:

In [2]: a = {randint(1, 10000000) for _ in range(1000000)}

In [3]: len(a)
Out[3]: 951498

In [4]: %timeit randint(1, 10000000) in a
1.86 µs ± 19.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)


Для множества из почти миллиона целых чисел время поиска случайного числа составляет в среднем 1.86 µs. Теперь сделаем замеры для множества из ста целых чисел, т.е. в 10 000 раз меньше:

In [5]: a = {randint(1, 10000000) for _ in range(100)}

In [6]: len(a)
Out[6]: 100

In [7]: %timeit randint(1, 10000000) in a
1.75 µs ± 13.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)


Из этих замеров видно, что время поиска элемента практически не зависит от количества элементов в коллекции, т.е. равно O(1). Поиск ключа в словаре работает с аналогичной скоростью.

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

#python #оптимизация