Эквивалентность Python для встроенных функций или макросов - PullRequest
44 голосов
/ 22 июня 2011

Я только что понял, что выполнение

x.real*x.real+x.imag*x.imag

в три раза быстрее, чем выполнение

abs(x)**2

, где x - это простой массив комплексных чисел.Для читабельности кода я мог бы определить функцию типа

def abs2(x):
    return x.real*x.real+x.imag*x.imag

, которая все еще намного быстрее, чем abs (x) ** 2, но за счет вызова функции.Можно ли встроить такую ​​функцию, как я сделал бы в C, используя макрос или ключевое слово inline?

Ответы [ 6 ]

32 голосов
/ 22 июня 2011

Можно ли встроить такую ​​функцию, как я делал бы в C, используя макрос или ключевое слово inline?

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

Как отмечается в комментариях, PyPy будет автоматически вставлять (приведенное вышедержится - он «просто» генерирует оптимизированную версию во время выполнения, получает от нее выгоду, но вылетает из нее, когда она становится недействительной), хотя в данном конкретном случае это не помогает, поскольку реализация NumPy на PyPy началась только недавно и недаже бета-уровень по сей день.Но суть в следующем: не беспокойтесь об оптимизации на этом уровне в Python.Либо реализации оптимизируют это сами, либо нет, это не ваша ответственность.

13 голосов
/ 26 октября 2016

Не совсем то, что запросил OP, но закрытие:

Inliner встроенные вызовы функций Python.Подтверждение концепции этого сообщения в блоге

from inliner import inline

@inline
def add_stuff(x, y):
    return x + y

def add_lots_of_numbers():
    results = []
    for i in xrange(10):
         results.append(add_stuff(i, i+1))

В приведенном выше коде функция add_lots_of_numbers конвертируется в:

def add_lots_of_numbers():
    results = []
    for i in xrange(10):
         results.append(i + i + 1)

Также всех, кто интересуетсяэтот вопрос и сложности, связанные с реализацией такого оптимизатора в CPython, возможно, также захотят взглянуть на:

6 голосов
/ 24 июня 2011

Я согласен со всеми остальными, что такая оптимизация просто вызовет у вас боль на CPython , что если вы заботитесь о производительности, вы должны рассмотреть PyPy (хотя наш NumPy может быть слишком неполным, чтобы быть полезным).Однако я не соглашусь и скажу, что вы можете заботиться о таких оптимизациях в PyPy, а не об этой, как было сказано, PyPy делает это автоматически, но если вы хорошо знаете PyPy, вы действительно можете настроить свой код так, чтобы PyPy испускал нужную сборкуне то, что вам нужно почти всегда.

5 голосов
/ 22 июня 2011

На самом деле это может быть даже быстрее, например:

x.real** 2+ x.imag** 2

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

In []: n= 1e4
In []: x= randn(n, 1)+ 1j* rand(n, 1)
In []: %timeit x.real* x.real+ x.imag* x.imag
10000 loops, best of 3: 100 us per loop
In []: %timeit x.real** 2+ x.imag** 2
10000 loops, best of 3: 77.9 us per loop

И инкапсуляция вычисления в функции:

In []: def abs2(x):
   ..:     return x.real** 2+ x.imag** 2
   ..: 
In []: %timeit abs2(x)
10000 loops, best of 3: 80.1 us per loop

В любом случае (как уже указывали другие) этот вид микрооптимизации (во избежание вызова функции) не является действительно продуктивным способом написания кода на Python.

5 голосов
/ 22 июня 2011

Нет.

Наиболее близким к макросам C, который вы можете получить, является скрипт (awk или другой), который вы можете включить в make-файл и который заменяет определенный шаблон, например abs (x) ** 2ваши скрипты на python с длинной формой.

0 голосов
/ 24 июня 2019

Вы можете попробовать использовать lambda:

abs2 = lambda x : x.real*x.real+x.imag*x.imag

затем позвоните по номеру:

y = abs2(x)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...