«Если необходимо, чтобы Ваш код работал быстрее,то вероятно, следует просто использовать PyPy»
Гвидо ван Россум (создатель Python).
Любой код, в первую очередь, должен быть написан обдуманно и быть рабочим и только потом можно приступать к его дополнительной оптимизации. При этом оптимизация должна проходит прямо в процессе разработки, так как потом сложно будет изменить множество мелких моментов.
Оптимизация производительности в любом языке программирования не имеет четкого алгоритма действий. Иногда даже незначительные изменения в «нужном месте» могут ускорить работу кода Python в несколько раз. Оптимизация кода — это придание важности мелочам.
Избегайте применение глобальных переменных.
Python очень медленно обрабатывает доступ к глобальным переменным, особенно внутри циклов. Также множественное применение глобальных переменных очень часто приводит к спагетти-коду, что вызывает дополнительные трудности и проблемы.
Лучшие способы Ускорить и Оптимизировать Python код
Использование сторонних модулей и библиотек.
Обращайте внимание на каком языке написан сторонний модуль или библиотека. Если есть возможность, то используйте библиотеки, написанные на С, так как они работают быстрее, а это значит, что и программа на Python будет работать немного быстрее.
Активно используйте встроенные инструменты Python.
Их применение ускоряет код за счет того, что они предварительно оптимизированы, скомпилированы и следовательно выполняются быстрее.
Примером таких инструментов может быть:
- встроенная функция map() ;
- встроенная функция str.join() ;
- встроенный модуль itertools ;
- и многое другое.
Работа над кодом.
- пишите код обдуманно и максимально лаконично;
- по возможности, внедряйте кэширование объектов;
- не создавать лишние экземпляры объектов (помните, объекты потребляют дополнительную память);
Перевод статьи словацкого разработчика Мартина Хайнца, в которой он описывает девять практических советов о том, как сделать разработку на Python лучше.
Обрабатывайте входные данные.
Чем больше размер программы, тем выше шансы пропустить уязвимость в коде. Один из способов обезопасить себя от возможных ошибок — очистка входных данных перед выполнением программы (input sanitization). В большинстве случаев при таком подходе достаточно поменять регистр символов или использовать регулярные выражения. Но для сложных случаев есть и более эффективный способ:
user_input = «Thisnstring hastsome whitespaces. rn» character_map = ord(‘n’) : ‘ ‘, ord(‘t’) : ‘ ‘, ord(‘r’) : None > user_input.translate(character_map)
Это пример заменяет «пробельные» символы n и t обычным пробелом и удаляет r (все перечисленные конструкции обозначают разные виды пробелов). В зависимости от задач, можно генерировать таблицы соответствий разного размера. Задачу облегчает встроенный модуль unicodedata и функция combining() для генерации и отображения. Их можно использовать для удаления всех акцентов из строки.
Как улучшить Питон код ОДНИМ словом? Как ускорить Python код легко?
Используйте итераторы со срезами.
Итератор — это инструмент для поточной обработки данных. Он отвечает за упрощение навигации по элементам: списку, словарю и так далее. Это такой объект-перечислитель, который выдаёт следующий элемент. В основном его используют в цикле for/in .
Но использовать итератор на полную мощность нужно не всегда. И тут незадача: если попытаться использовать срез итератора, то получим ошибку TypeError . Это произойдёт из-за того, что объект итератора не является подписываемым. К счастью, на такой случай есть простое решение:
import itertools s = itertools.islice(range(50), 10, 20) for val in s: .
Используя itertools.islice() , можно создать объект islice , который сам по себе является итератором, производящим нужные значения. Важно отметить, что этот объект использует все элементы генератора вплоть до начала среза, что делает itertools.islice() мощным инструментом.
Пропускайте начало итерируемого объекта.
Иногда приходится работать с файлами, которые начинаются с неизвестного количества бесполезных строк, например, с комментариев. И тут модуль itertools снова предлагает простое решение:
Этот фрагмент кода создаёт строки, пропуская начальные комментарии. Такой подход может быть полезен, если нужно отбросить элементы (в нашем случае строки) в начале итерируемого объекта.
Используйте kwargs .
Если при разработке программы нужно выполнить несколько похожих действий, то лучшее решение — определить функции для многократного использования в коде. Для этого создается функция с аргументами. Но что делать, если аргументы функции определены, а для ее многократного использования (унификации) нужно передавать разное количество аргументов? Для этого можно использовать ключевые аргументы функции kwargs .
Этот инструмент очень пригодится для создания функции только с именованными аргументами. Это даст возможность (или, скорее, обяжет) использовать такие функции более прозрачно:
def test(*, a, b): pass test(«value for a», «value for b») # Traceback (most recent call last): # File «ad.py», line 4, in # test(«value for a», «value for b») # TypeError: test() takes 0 positional arguments but 2 were given test(a=»value1″, b=»value2″) # Работает.
Как видно из примера, задачу легко решить, если поместить аргумент * перед ключевыми словами. И, конечно, можно использовать позиционные аргументы, если вставить их до аргумента * .
Используйте объекты, которые поддерживают оператор with .
Открыть файл и заблокировать фрагмент кода можно с помощью оператора with , но можно ли сделать это, пользуясь собственным методом? Да, можно реализовать протокол context manager, используя методы __enter__ и __exit__ :
class Connection: def __init__(self): . def __enter__(self): # инициализация соединения def __exit__(self, type, value, traceback): # закрытие соединения # использование with Connection() as conn: # __enter__() executes . # conn.__exit__() executes
Это распространённый вариант управления контекстом в Python, но есть и более простой способ:
Этот фрагмент кода реализует протокол управления контекстом, используя декоратор менеджера contextmanager . Первая часть функции tag() (до yield ) выполняется при входе в блок with , затем исполняется блок, а после него и остальная часть функции tag() .
Сохраните всё с помощью __slots__ .
Если программа создаёт большое количество инстансов какого-либо класса, то она может потребовать больше памяти. Это связано с тем, что Python использует словари для представления атрибутов инстансов классов. Это делает язык быстрым, но не очень эффективным с точки зрения оптимизации памяти. Если это становится проблемой, то поможет магический атрибут __slots__ :
class Person: __slots__ = [«first_name», «last_name», «phone»] def __init__ (self, first_name, last_name, phone): self.first_name = first_name self.last_name = last_name self.phone = phone
При определении атрибута __slots__ Python использует небольшой массив фиксированного размера для атрибутов вместо словаря. Это значительно сокращает объём памяти, необходимый для каждого инстанса.
Следует учесть, что в этом случае есть и недостатки: нельзя объявлять какие-либо новые атрибуты помимо используемых в __slots__ , а классы со __slots__ не могут использовать множественное наследование.
Ограничьте использование процессора и памяти.
Если лень оптимизировать память программы или корректировать работу процессора, то можно просто установить лимиты. К счастью, в Python для этого есть специальный модуль resource :
import signal import resource def time_exceeded(signo, frame): print(«CPU exceeded. «) raise SystemExit(1) def set_max_runtime(seconds): soft, hard = resource.getrlimit(resource.RLIMIT_CPU) resource.setrlimit(resource.RLIMIT_CPU, (seconds, hard) ) signal.signal(signal.SIGXCPU, time_exceeded) def set_max_memory(size): soft, hard = resource.getrlimit(resource.RLIMIT_AS) resource.setrlimit(resource.RLIMIT_AS, (size, hard))
Здесь можно увидеть две опции: установку на максимальное процессорное время и максимальный предел используемой памяти.
При ограничении работы процессора необходимо извлечь мягкий и жёсткий лимиты для конкретного ресурса ( resource.RLIMIT_CPU ), а затем установить его значение. Для этого используется количество секунд, указанное в аргументе, и ранее полученное жёсткое ограничение. В конце нужно зарегистрировать сигнал, который будет отвечать за выход из системы, если процессорное время превышено.
Что касается памяти, то, как и в случае с процессором, устанавливаем мягкий и жёсткий лимиты. Для этого используется функция resource.setrlimit() с аргументом size и жёсткое ограничение, которое было получено.
Управляйте экспортом элементов.
Такие языки программирования, как Go, имеют механизм экспорта только для элементов (переменных, методов, интерфейсов) начинающихся с заглавной буквы. В Python подобного можно добиться с помощью переменной __all__ :
def foo(): pass def bar(): pass __all__ = [«bar»]
В данном случае, благодаря __all__ экспортирован будет не весь код, а только функция bar() . Кроме того, можно оставить переменную пустой, то при попытке импорта из этого модуля ничего не попадёт в экспорт, что приведёт к ошибке AttributeError .
Упростите использование операторов сравнения.
Использовать все операторы сравнения для одного класса может быть довольно сложно, учитывая, что их немало: __lt__ , __le__ , __gt__ или __ge__ . Но есть ли более простой способ сделать это? Здесь поможет functools.total_ordering :
Источник: docs-python.ru
Десять способов для ускорения кода на Python
В последние годы было приложено много усилий для улучшения производительности Python. Сейчас можно быстро обрабатывать большие наборы данных, используя библиотеки numpy, scipy, pandas, numba . А также Pypy , которая ускоряет выполнение кода на Python, в несколько раз.В этой статье я поделюсь десятью способами ускорения Python без использования сторонних инструментов. Приведенные в данной статье примеры доступны в этом репозитории на Github .1. Познакомьтесь со встроенными функциями
Python поставляется с множеством встроенных функций, реализованных на языке программирования C, которые очень быстры и хорошо поддерживаются (рисунок 1). Например, функции, связанные с алгебраическими вычислениями: abs(), len(), max(), min(), set(), sum()).
В качестве примера рассмотрим встроенные функции set() и sum(). Их использование позволяет повысить скорость выполнения кода в десятки раз.
2. sort() или sorted()
Обе функции предназначены для сортировки списков. Функция sort() немного быстрее, чем sorted(). Это связано с тем, что метод sort() изменяет первичный список. sorted() создает новый отсортированный список и оставляет исходный список без изменений.
Но функция sorted() более универсальна. Она принимает любую коллекцию, в то время как функция sort()работает только со списками. Например, с помощью sorted() можно быстро отсортировать словарь по его ключам или значениям.
Использование sorted() со словарем
3. Используйте символы вместо функций
Для создания пустого словаря или списка вместо dict() или list() можно использовать фигурные скобки «<>». Как и для пустого набора, когда нужно использовать set()) и [].
4. Генератор списков
Для создания нового списка из старого списка мы используем цикл for. Он позволяет перебрать старый список, преобразовать его значения на основе заданных условий и сохранить в новом списке. Например, чтобы найти все четные числа из another_long_list, можно использовать приведенный ниже код:
Но есть более лаконичный способ переборки. Для его реализации мы помещаем исходный цикл for всего в одну строку кода. При этом скорость выполнения увеличивается почти в 2 раза.
В сочетании с третьим способом мы можем превратить список в словарь или набор, изменив [] на <>. Давайте перепишем код с рисунка 5. Мы можем пропустить присвоение и завершить итерацию внутри скобок. Например,sorted_dict3 = .
Функция sorted(a_dict.items(), key=lambda item: item[1]) вернет список кортежей (рисунок 4). Здесь мы используем множественное присваивание для распаковки кортежей. Так как каждому кортежу в списке мы присваивали ключ его первому элементу и значение его второму элементу. После этого каждая пара ключ-значение сохраняется в словаре.
5. Используйте функцию enumerate() для получения значений и индексов
Можно использовать функцию enumerate(), которая превращает значения списка в пары index и value. Это также ускорит Python-код примерно в 2 раза.
Рисунок | Пример enumerate()
6. Используйте zip() для слияния списков
Иногда нужно перебирать два списка или даже более. Для этого можно использовать функцию zip(), которая преобразует несколько списков в один список кортежей. При этом спискам лучше иметь одинаковую длину, иначе выполнение zip() остановится, как только закончится самый короткий список.
Чтобы получить доступ к элементам в каждом кортеже, можно разделить список кортежей, добавив звездочку (*) и используя несколько переменных. Например, letters1, numbers1 = zip(*pairs_list).
7. Совмещайте set() и in
Для проверки наличия определенного значения часто пишется подобная функция:
Затем вызывается метод check_membership(value), чтобы увидеть, есть ли значение в another_long_list. Но лучше просто использовать in, вызвав value in another_long_list.
Проверка вхождения, с помощью in и set()
Для большей эффективности необходимо сначала удалить дубликаты из списка с помощью set(), а затем проверить вхождение в объекте набора. Так мы сократим количество элементов, которые необходимо проверить.
8. Проверка переменной на истинность
Для проверки пустых переменных, списков, словарей не нужно явно указывать == True или is True в операторе if. Вместо этого лучше указать имя переменной.
Простая проверка переменной
Если нужно проверить, является ли переменная пустой, используйте if not string_returned_from_function.
9. Для подсчета уникальных значений используйте Counters()
Чтобы подсчитать уникальные значения в списке a_long_list, который мы создали в пункте 1, нужно создать словарь. Его ключи являются числами, а значения – счетчиками. Выполняя проход по списку, увеличиваем значение счетчика, если элемент уже есть в словаре. А также добавлять его в словарь, если его там нет.
Но более эффективный способ сделать это – использовать подкласс Counter() из библиотеки коллекций :
Чтобы получить десять наиболее часто встречающихся чисел, используйте метод most_common, доступный в Counter().
Для подсчета уникальных значений используйте Counters()
10. Вложите цикл for внутрь функции
Предположим, что мы создали функцию, и нам необходимо вызвать ее определённое количество раз. Для этого функция помещается в цикл for.
Но вместо выполнения функции миллион раз (длина a_long_list составляет 1 000 000), можно интегрировать цикл for внутрь функции. Это сэкономит около 22% времени.
Рисунок 12 | цикл for внутри функции
Надеюсь, что некоторые из перечисленных способов ускорения выполнения кода Python окажутся полезными для вас.
Источник: dzen.ru
7 простых способов оптимизировать код Python
Python использует хеш-таблицы для управления множествами. Всякий раз, когда мы добавляем элемент в множество, интерпретатор Python определяет его позицию в памяти, выделенной для множества, используя хэш целевого элемента.
Поскольку Python автоматически изменяет размер хеш-таблицы, скорость будет постоянной (O (1)) вне зависимости от размера набора. Именно это ускоряет выполнение операций.
В Python операции с множествами включают объединение, пересечение и разность. Поэтому вы можете попробовать использовать их в своем коде – там, где это возможно. Обычно эти операции работают быстрее, чем итерации по спискам.
2. Избегайте использования глобальных переменных.
Это не касается не только Python, почти все языки не одобряют чрезмерное или незапланированное использование глобальных переменных. Причина в том, что у них могут быть скрытые / неочевидные побочные эффекты, ведущие к коду Спагетти. Плюс ео всему, Python очень медленный при доступе к внешним переменным.
Это вынуждает ограничить использование глобальных переменных. Можно объявить внешнюю переменную, используя ключевое слово global (что тоже не всегда правильно ).
Кроме того, лучше сделать локальную копию, прежде чем использовать глобальные переменные внутри циклов.
3. Использование внешних библиотек / пакетов.
Некоторые библиотеки python имеют эквивалент «C» с теми же функциями, что и исходная библиотека. Будучи написаны на “C”, они работают быстрее. Например, попробуйте использовать cPickle вместо использования pickle.
Можно использовать , который является оптимизирующим статическим компилятором для обоих Python. Это расширение Python, поддерживающее функции и типы C. Код на нем выполняется быстрее и эффективнее.
Также можно использовать пакет PyPy. Он включает компилятор JIT (Just-in-time), который делает код Python невероятно быстрым. PyPy можно дополнительно настроить для еще большего повышения производительности.
4. Используйте встроенные модули и функции.
Python является интерпретируемым языком и основан на абстракциях высокого уровня. Поэтому лучше использовать встроенные модули везде, где это возможно. Это сделает код более эффективным, поскольку встроенные модули предварительно компилируются и выполняются быстро. В то время как длительные итерации, которые включают интерпретируемые шаги, выполняются очень медленно.
Аналогичным образом, предпочтительно использовать встроенные функции, такие как, например, map, которые значительно ускоряют код
5. Ограничьте поиск в методе с использованием цикла
При работе в цикле нужно кэшировать вызов метода, а не вызывать метод для объекта. В противном случае поиск получится дороговатым.
Просто взгляните на этот пример, и сразу станет понятно, о чем речь.
6. Оптимизация использования строк.
Конкатенация строк идет медленно, никогда не делайте это внутри цикла. Вместо этого используйте метод join. Или используйте функцию форматирования для формирования унифицированной строки.
Операции RegEx в Python выполняются быстро, поскольку они в конечном итоге приходят к C-коду. Однако, в некоторых случаях, основные методы строки, такие как , работают лучше.
Кроме того, можно проверить различные методы, используя модуль . Это поможет определить, какой метод действительно самый быстрый.
7. Оптимизация при помощи оператора if.
Как и в большинстве языков программирования, в Python есть “ленивая” оценка. Это означает, что если есть цепочка условий «and», то проверка остановится на первом ложном условии.
Это поведение Python можно использовать в целях опитмизации кода . Например, если вы ищете фиксированный шаблон в списке, можно уменьшить область поиска, добавив условие «and», которое становится ложным, если размер целевой строки меньше длины шаблона.
Источник: pylab.ru