Оптимизация кода на Python

Естественно, самым эффективным будет оптимизация алгоритма, но это индивидуально, посему имеет смысл привести общие советы:

  1. Сокращение повторений операций. Например:
    for i in range(n):
        for j in range(n):
            if (i * j < 200):
                p = i * j
    
    можно ускорить как:
    for i in range(n):
        for j in range(n):
            tmp = i * j
            if (tmp < 200):
                p = tmp
    
  2. Помним, что Python обладает сокращенной моделью вычисления условий. То есть, если на некотором этапе условной конструкции уже можно дать ответ, остальную часть конструкции он выполнять не будет. Например:
    for i in range(n):
        for j in range(n):
            if (a[i][i]*n != 100 and i < j):
                count = 0
    
    можно значительно перестановкой условий, ибо первое затратно на вычисления:
    for i in range(n):
        for j in range(n):
            if (i < j and a[i][i]*n != 100):
                count = 0
    
  3. При оптимизации полезен модуль profile. С помощью его можно получать статистику вызывов функций и времени выполнения. Таким образом, он поможет найти "узкие" места алгоритма. Иногда сии манипуляции называют "профилирование". Пример использования:
    import profile
    profile.run('main()')

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

  1. Иногда для часто вызываемых встроенных функций удобно создать псевдоним в локальном пространстве функции:
    temp =''
    for i in range(n):
        for j in range(n):
            temp += str(a[i][j])
    
    можно ускорить:
    lstr = str
    temp =''
    for i in range(n):
        for j in range(n):
            temp += lstr(a[i][j])
    
  2. Пользуйтесь по возможности xrange вместо range — он более бережно использует память.
  3. Вынос основного кода python в отдельную функцию помогает интерпретатору python лучше проводить внутренние оптимизации:
    n = 400
    A = init_A(n)
    for i in range(n):
            A[i][i] *= n * n
    B = init_B(n)
    printToFile(A,B,n)
    
    работает быстрее, если переписать:
    def run():
        n = 400
        A = init_A(n)
        for i in range(n):
            A[i][i] *= n * n
        B = init_B(n)
        printToFile(A,B,n)
    
    run()
  4. Работа с глобальными переменными медленней работы с локальными.
  5. Импорт объектов также лучше делать в локальном пространстве функции.
  6. Пользуйтесь встроенными функциями — многие написаны на C и работают быстрее.
  7. Заменяйте "общие" функции на конкретные:
    p = math.sqrt(x ** 2 + y ** 2)
    на
    p = math.sqrt(x * x + y * y)
  8. Заменяйте цикл for на map() где возможно — она написана на C.
  9. При работе с большими массивами чисел используйте NumPy. Для линейной алгебры полезно использовать ATLAS — результаты потрясающие. Подробнее тут.
  10. Старайтесь, чтобы функции обрабатывали агрегаторы данных:
    for i in xrange(n):
        func(a[i])
    лучше заменить на:
    func(a)
  11. Кортежи и списки: кортежи неизменяемы, списки — изменяемы. Если данные не будут меняться — используйте кортежи.

В заключение — оптимизировать стоит уже готовый, отлаженный код. И не забывайте про JIT-компиляцию: отличная реализация для Python — PyPy.

Почитать:
http://wiki.python.org/moin/PythonSpeed
http://wiki.python.org/moin/PythonSpeed/PerformanceTips