Есть ли в python инструмент, эквивалентный c поведению препроцессора в C? - PullRequest
1 голос
/ 03 мая 2020

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

int f(int x, int y, char z, char *w);
int g(int x, int y, char z, char *w);
int h(int x, int y, char z, char *w);
int i(int x, int y, char z, char *w);
int j(int x, int y, char z, char *w);

Оставить открытой возможность добавления дополнительного параметра к каждой из этих Функции, не меняя много строк кода, я могу использовать препроцессор, чтобы оставаться гибким:

#define FUNCTION(func) int (func)(int x, int y, char z, char *w)

, а затем заменить мои прототипы на

FUNCTION(f);
FUNCTION(g);
FUNCTION(h);
FUNCTION(i);
FUNCTION(j);

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

FUNCTION(f)
{
    //do something with x,y,z,w
}

FUNCTION(g)
{
    //do something else with x,y,z,w
}

Есть ли способ выполнить sh это в python? то есть возможно ли определить множество функций в Python, все из которых принимают одинаковые параметры, а затем изменить их параметры (скажем, добавить или удалить одну), изменив одну строку?

Ответы [ 2 ]

3 голосов
/ 03 мая 2020

Вы не объявляете функции вперед в Python, как в C, поэтому предпосылка этого вопроса не имеет большого смысла. Самая близкая аналогия была бы в объявлениях типов, которые вы можете использовать в качестве псевдонима:

from typing import Callable

FUNCTION = Callable[[int, int, str, str], int]

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

Для случая, который вы описываете при редактировании, вы можете просто не объявлять типы аргументов и использовать вместо них * args:

def f(*args):
    x, y, z, w = args

Или для безопасного типа решения (поскольку трудно набирать * args и ** kwargs), вы можете сделать так, чтобы эти функции принимали один (типизированный) аргумент кортежа:

FUNCTION_ARGS = Tuple[int, int, str, str]

def f(args: FUNCTION_ARGS):
    # next line will throw a mypy error if it doesn't match FUNCTION_ARGS
    x, y, z, w = args  
1 голос
/ 03 мая 2020

Стандарт Python не имеет встроенных средств макросов и не поддерживает стати c генеративное метапрограммирование, за исключением eval / exec.

За исключением eval/exec Python обеспечивает только динамическое метапрограммирование c (во время выполнения), и, очевидно, это выбор дизайна; например, он предоставляет декораторы, которые могут охватывать некоторые случаи использования. Кроме того, чтение (синтаксический анализ) исходного кода Python отлито в камень, и нет никакого способа расширить синтаксис.

Простой способ создания функций и классов во время выполнения состоит в создании исходного кода для них как текстовая строка и вызывая eval или exec на нем. Это то, что стандартная библиотека делает, например, для namedtuple.

Кроме того, раскрываются почти все низкоуровневые части виртуальной машины Python; у вас есть доступ к Python байт-коду, и вы можете, например, генерировать функции таким образом, но это довольно сложная операция, потому что вам нужно заботиться о многих деталях (например, эффект стека), и, кроме того, некоторые из этих внутренних компонентов не гарантированно стабильны между Python версиями. Теоретически возможно переопределить exec в самом Python, используя только Python, но это будет довольно сложно, потому что вы переписываете значительную часть Python компилятора (который написан на C) самостоятельно .

Есть также кто-то, кто пытался добавить мощность макроса к Python, просто используя то, что обеспечивает Python (или забыл запретить) ... У меня нет опыта работы с ним. однако.

...