doggo
doggo

Reputation: 105

Is there an equivalent tool in python to mimic the behaviour of the pre-processor in C?

It is not uncommon to want to define many different functions which shall have the same prototype in 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);

To leave open the possibility of adding an additional parameter to every single one of these functions without having to change many lines of code, I can use the preprocessor to stay flexible:

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

and then replace my prototypes with

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

And then when I go to define the functions I would use lines like:

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

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

Is there a way to accomplish this in python? i.e. is it possible define many functions in Python, all of which take exactly the same parameters, then modify their parameters (say adding or removing one) by changing a single line?

Upvotes: 1

Views: 259

Answers (2)

6502
6502

Reputation: 114519

Standard Python has no built-in macro facilities and no support for static generative meta-programming except for eval/exec.

With the exclusion of eval/exec Python only provides dynamic (run-time) metaprogramming and apparently this is a design choice; for example it does provide decorators, that can cover some use cases. Also the reading (parsing) of Python source code is cast in stone and there's no way to extend the syntax.

The easy way to create functions and classes at runtime is by building the source code for them as a text string and invoking eval or exec on it. This is what the standard library does for example for namedtuple.

In addition almost all of the low-level parts of the Python VM are exposed; you have access to Python bytecode and you can for example generate functions that way, but that's a quite challenging operation because you need to take care about a lot of details (e.g. stack effect) and moreover some of those internals are not guaranteed stable between Python versions. It's in theory possible to reimplement exec in Python itself using only Python, but that would be quite difficult because you've to rewrite a sizeable part of Python compiler (that is written in C) yourself.

There is also someone that tried to add macro power to Python just using what Python provides (or forgot to forbid)... I've no experience with it however.

Upvotes: 1

Samwise
Samwise

Reputation: 71464

You don't forward-declare functions in Python the way you might in C, so the premise of this question doesn't make a lot of sense. The closest analogy would be in type declarations, which you can indeed alias:

from typing import Callable

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

You can also have functions that themselves return functions, and potentially eliminate a lot of repetition that way, but your example doesn't include the body of the functions so that doesn't really map.

For the case you describe in your edit, you could just not declare the argument types and use *args instead:

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

Or for a typesafe solution (since it's hard to type *args and **kwargs), you could have these functions take a single (typed) tuple argument:

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  

Upvotes: 3

Related Questions