14

I use to define macros (not just constants) in C like

#define loop(i,a,b) for(i=a; i<b; ++i)
#define long_f(a,b,c) (a*0.123 + a*b*5.6 - 0.235*c + 7.23*c - 5*a*a + 1.5)

Is there a way of doing this in python using a preprocess instead of a function?

*By preprocess I mean something that replaces the occurrences of the definition before running the code (actually not the whole code but the rest of the code, because since it's part of the code, I guess it will replace everything during runtime).

If there is, worth it? Will there be a significant difference in run time?

3
  • 2
    Traditionally the C preprocessor was a separate program, and it's still available as cpp in most POSIX-like systems. There are of course many other preprocessors available, M4 being the most notable these days. There are also other C-like preprocessors if you just search a little. However, most Python programmers would frown at you and your code if you used a preprocessor and macros like that. Most C programmers as well actually. Commented Apr 8, 2016 at 4:51
  • 1
    Python is an interpreted language, there isn't a concept of a C-like pre-processor that replaces tokens before compilation. Commented Apr 8, 2016 at 4:54
  • 1
    Have a look at github.com/trentm/preprocess . Commented Jan 24, 2018 at 17:13

5 Answers 5

10

Is there a way? Yes. There's always a way. Should you do it? Probably not.

Just define a function that does what you want. If you are just concerned about code getting really long and want a one-liner, you can use a lambda function.

long_f = lambda a,b,c: a*0.123 + a*b*5.6 - 0.235*c + 7.23*c - 5*a*a + 1.5
long_f(1,2,3) == 28.808

And of course your first example is already way prettier in Python.

for i in range(a,b):
    ...

Edit: for completeness, I should answer the question as asked. If you ABSOLUTELY MUST preproccess your Python code, you can use any programming language designed for templating things like web pages. For example, I've heard of PHP being used for preprocessing code. Instead of HTML, you write your code. When you want something preprocessesed, you do your PHP blocks.

Sign up to request clarification or add additional context in comments.

Comments

8

Well, if you're going to perform some really hard calculations that could be performed in advance, then, perhaps, this makes sense: usually users are more happy with fast programs rather than slow ones.

But, I'm afraid python isn't a good choice when it comes to 'raw performance', that is, speed of arithmetic calculations. At least if we talk about the standard python implementation, called CPython.

Alternatively, you could check other variants:

  • PyPy. This is an alternative python implementation, in pure Python. Thanks to a JIT compiler it gives better performance but requires a lot more memory.
  • Cython. This is an extension to Python, which allows one to [conveniently] create compileable snippets for perfomance critical parts of the code.
  • Use a whatever external pre-processor you like. M4 and FilePP are what come to my mind first, but there're plenty of them.

Comments

1

There is nothing in Python 100% equivalent to macro in C. But there is a makeshift using exec().

Say we want to compute the addition and multiplication of all the elements of a 4-D matrix. Normally we can define the functions like

import numpy as np

def Addition(matrix):
    result=0
    for i in range(matrix.shape[0]):
        for j in range(matrix.shape[1]):
            for k in range(matrix.shape[2]):
                for l in range(matrix.shape[3]):
                    result+=matrix[i,j,k,l]
    return result

def Multiplication(matrix):
    result=1
    for i in range(matrix.shape[0]):
        for j in range(matrix.shape[1]):
            for k in range(matrix.shape[2]):
                for l in range(matrix.shape[3]):
                    result*=matrix[i,j,k,l]
    return result

The 4-fold loop appears twice but I want it to appear only once for conciseness. In C/C++, we would replace it with a macro like

#define Loop\
    for (i=0;i<imax;i++)\
        for (j=0;j<jmax;j++)\
        ........

In Python, we can use exec() instead. This function takes in a string and execute it as a command. So the codes become

import numpy as np

string='''
for i in range(matrix.shape[0]):
    for j in range(matrix.shape[1]):
        for k in range(matrix.shape[2]):
            for l in range(matrix.shape[3]):
                __replacement__
'''

def Addition(matrix):
    result=np.zeros([1])
    exec(string.replace("__replacement__","result[0]+=matrix[i,j,k,l]"))
    return result[0]

def Multiplication(matrix):
    result=np.zeros([1])+1
    exec(string.replace("__replacement__","result[0]*=matrix[i,j,k,l]"))
    return result[0]

Here, the 4-fold loop appears only once as a global string variable. BUT BE WARNED. There is one problem: The result must be a np.array. If you initialize result as an ordinary float like result=0. and result=1., the exec() function will not change it and the initial values 0 and 1 will be returned in the end. This is probably a problem with the difference between reference and value. Besides, I don't expect any performance gain from this replacement. The only advantage is convenience in coding replicated commands, which may be useful in some scenarios.

Comments

0

The answer is no, in python you cannot actually include code "in-line/stream/whatever" like in C, C++, PL/1, Assembler, etc.. Implementation of this directive happens during an initial macro/processor/keyword scan or compiler pass. It could easily be added, and there are lots of reasons one might wish to include code directly inline without it being a function or module. This feature would make it possible to use the same snippet of code in multiple class or function definitions. For example defining the same GTK+ elements within multiple classes are a pain without it. This lack of ability has nothing to do with interpretation, because it occurs prior to syntactic analysis. It is not included in interpreted script languages such as Perl and Python simply because the developers do not want to make the feature available.

Comments

-1
import inspect

frame = inspect.currentframe()
print(f"{frame.f_lineno}\tdebugtext")
l = lambda: frame.f_lineno
print(f"{l()}\tdebugtext")

1 Comment

Answer needs supporting information Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.