В программе на C вставка функции является довольно интуитивной оптимизацией. Если тело встроенной функции достаточно мало, вы в конечном итоге сохраняете переход к функции и создаете кадр стека и сохраняете возвращаемое значение везде, где был бы сохранен результат функции, переходя в конец тела встроенной функции. "вместо длинного перехода к указателю возврата.
Я заинтересован в том, чтобы сделать то же самое в Python, преобразовав две функции python в другую допустимую функцию python, где первая «встроена» во вторую. Идеальное решение этого может выглядеть примерно так:
def g(x):
return x ** 2
def f(y):
return g(y + 3)
# ... Becomes ...
def inlined_f(y):
return (y + 3) ** 2
Очевидно, что на языке, таком динамическом, как Python, это не просто сделать автоматически. Лучшее общее решение, которое я придумала, это использовать dict
для захвата аргументов, переданных функции, обернуть тело функции в одноповторный цикл for
, использовать break
для перехода к концу функции и замените использование аргументов индексами в словарь аргументов. Результат выглядит примерно так:
def inlined_f(y):
_g = dict(x=y + 3)
for ____ in [None]:
_g['return'] = _g['x'] ** 2
break
_g_return = _g.get('return', None)
del _g
return _g_return
Мне все равно, что это некрасиво, но мне важно, чтобы оно не поддерживало возвраты из циклов. E.g.:
def g(x):
for i in range(x + 1):
if i == x:
return i ** 2
print("Woops, you shouldn't get here")
def inlined_f(y):
_g = dict(x=y + 3)
for ____ in [None]:
for _g['i'] in range(_g['x'] + 1):
if _g['i'] == _g['x']:
_g['return'] _g['i'] ** 2
break # <-- Doesn't exit function, just innermost loop
print("Woops, you shouldn't get here")
_g_return = _g.get('return', None)
del _g
return _g_return
Какой подход я мог бы применить к этой проблеме, чтобы избежать необходимости использовать break
, чтобы «выпрыгнуть» из тела встроенной функции? Я также был бы открыт для общего лучшего общего подхода, который я мог бы использовать, чтобы встроить одну функцию Python в другую.
Для справки, я работаю на уровне AST (абстрактного синтаксического дерева), поэтому использую анализируемый код Python; ясно, что вне литеральных значений я не знаю, какое значение или тип что-либо будет иметь при выполнении этого преобразования. Результирующая встроенная функция должна вести себя идентично исходным функциям и поддерживать все функции, обычно доступные при вызове функции. Возможно ли это даже в Python?
РЕДАКТИРОВАТЬ: я должен уточнить, так как я использовал тег «оптимизация», что я на самом деле не заинтересован в повышении производительности. Результирующий код не обязательно должен быть быстрее , он просто не должен вызывать встроенную функцию, все еще ведя себя идентично. Вы можете предположить, что исходный код обеих функций доступен как допустимый Python.