views:

742

answers:

5

Is there a way to do the following preprocessor directives in Python?

#if DEBUG

< do some code >

#else

< do some other code >

#endif
+13  A: 

I suspect you're gonna hate this answer. The way you do that in Python is

# code here
if DEBUG:
   #debugging code goes here
else:
   # other code here.

Since python is an interpreter, there's no preprocessing step to be applied, and no particular advantage to having a special syntax.

Charlie Martin
Being an interpreter doesn't have anything to do with it. Nobody claims Java is interpreted, yet Java uses exactly the same technique (the D language is another example). Python is in fact a compiler, it compiles source code to bytecode and executes it in a VM, just like Java.
Greg Hewgill
@Greg Hewgill: There's no value in preprocessor directives to finesse things like static type declarations or conditional code, since the one doesn't exist and the other doesn't represent a significant cost.
S.Lott
Greg, go back and think about that answer. (1) Java, unlike Python, has a *separate* compilation phase. (2) While they never became popular, there hae been several java preprocessors. ...
Charlie Martin
(con't) Now, as a quiz question, what makes a preprocessor more advantageous in C/C++ than Python?
Charlie Martin
+2  A: 

You can just use the normal language constructs:

DEBUG = True
if DEBUG:
  # Define a function, a class or do some crazy stuff
  def f():
    return 23
else:
  def f():
    return 42
phihag
+5  A: 

You can use the preprocessor in Python. Just run your scripts through the cpp (C-Preprocessor) in your bin directory. However I've done this with Lua and the benefits of easy interpretation have outweighed the more complex compilation IMHO.

Robert Gould
I agree, that sounds a lot more trouble than its worth!
intrepion
+15  A: 

There's __debug__, which is a special value that the compiler does preprocess.

if __debug__:
  print "If this prints, you're not running python -O."
else:
  print "If this prints, you are running python -O!"

__debug__ will be replaced with a constant 0 or 1 by the compiler, and the optimizer will remove any if 0: lines before your source is interpreted.

Aaron Gallagher
+1 for learning something new.
David
Wow this definitely answers my question!
intrepion
The problem with the solution is that by default __debug__ is true, it is only false if you run python with the -O command line switch. I find that this switch is typically not used, which is not necessarily what a user would expect.
Moe
@Moe: It does seem that the logic of the flag is backwards. if __debug__ evaluates to True I would expect that I *am* running in debug mode, which is not the case.
Bill the Lizard
+2  A: 

I wrote a python preprocessor called pypreprocessor that does exactly what you're describing.

The source and documentation is available on Google Code.

The package can also be downloaded/installed through the PYPI.

Here's an example to accomplish what you're describing.

from pypreprocessor import pypreprocessor

pypreprocessor.parse()

#define debug

#ifdef debug
print('The source is in debug mode')
#else
print('The source is not in debug mode')
#endif

pypreprocessor is capable of a lot more than just on-the-fly preprocessing. To see more use case examples check out the project on Google Code.

Update: More info on pypreprocessor

The way I accomplish the preprocessing is simple. From the example above, the preprocessor imports a pypreprocessor object that's created in the pypreprocessor module. When you call parse() on the preprocessor it self-consumes the file that it is imported into and generates a temp copy of itself that comments out all of the preprocessor code (to avoid the preprocessor from calling itself recursively in an infinite loop) and comments out all of the unused portions.

Commenting out the lines is, as opposed to removing them, is necessary to preserve line numbers on error tracebacks if the module throws an exception or crashes. And I've even gone as far as to rewrite the error traceback to report reflect the proper file name of the module that crashed.

Then, the generated file containing the postprocessed code is executed on-the-fly.

The upside to using this method over just adding a bunch of if statements inline in the code is, there will be no execution time wasted evaluating useless statements because the commented out portions of the code will be excluded from the compiled .pyc files.

The downside (and my original reason for creating the module) is that you can't run both python 2x and python 3x in the same file because pythons interpreter runs a full syntax check before executing the code and will reject any version specific code before the preprocessor is allowed to run ::sigh::. My original goal was to be able to develop 2x and 3x code side-by-side in the same file that would create version specific bytecode depending on what it is running on.

Either way, the preprocessor module is still very useful for implementing common c-style preprocessing capabilities. As well as, the preprocessor is capable of outputting the postprocessed code to a file for later use if you want.

Also, if you want to generate a version that has all of the preprocessor directives as well as any of the #ifdefs that are excluded removed it's as simple as setting a flag in the preprocessor code before calling parse(). This makes removing unwanted code from a version specific source file a one step process (vs crawling through the code and removing if statements manually).

Evan Plaice