你如何在python中实现“#ifdef”?

时间:2012-09-21 05:08:09

标签: python preprocessor

C中的编程我以前只有用于调试目的的代码段(日志记录命令等)。可以使用#ifdef预处理器指令完全禁用这些语句,如下所示:

 #ifdef MACRO

 controlled text

 #endif /* MACRO */

python中执行类似操作的最佳方式是什么?

9 个答案:

答案 0 :(得分:25)

如果您只想禁用日志记录方法,请使用logging模块。如果将日志级别设置为排除,例如调试语句,则logging.debug将非常接近无操作(它只检查日志级别并返回而不插入日志字符串)。

如果你想在字节码编译时根据特定变量实际删除代码块,你唯一的选择是相当神秘的__debug__全局变量。除非将True标志传递给Python(或者-O在环境中设置为非空,否则此变量设置为PYTHONOPTIMIZE

如果在__debug__语句中使用if,则if语句实际上只编译到True分支中。这种特殊的优化与Python的预处理器宏一样接近。

请注意,与宏不同,您的代码在if的两个分支中仍必须在语法上正确。


要说明__debug__的工作原理,请考虑以下两个功能:

def f():
    if __debug__: return 3
    else: return 4

def g():
    if True: return 3
    else: return 4

现在使用dis

查看它们
>>> dis.dis(f)
  2           0 LOAD_CONST               1 (3)
              3 RETURN_VALUE        
>>> dis.dis(g)
  2           0 LOAD_GLOBAL              0 (True)
              3 JUMP_IF_FALSE            5 (to 11)
              6 POP_TOP             
              7 LOAD_CONST               1 (3)
             10 RETURN_VALUE        
        >>   11 POP_TOP             

  3          12 LOAD_CONST               2 (4)
             15 RETURN_VALUE        
             16 LOAD_CONST               0 (None)
             19 RETURN_VALUE        

如您所见,只有f被“优化”。

答案 1 :(得分:6)

重要的是要理解Python defclass是两个常规的可执行语句......

import os

if os.name == "posix":
    def foo(x):
        return x * x
else:
    def foo(x):
        return x + 42
...

因此,要使用C和C ++中的预处理器执行的操作,您可以使用常规Python语言。

Python语言在这一点上与C和C ++根本不同,因为没有"编译时间"并且只有两个阶段是"解析时间" (当读入源代码时)和"运行时间"当执行解析的代码(通常主要由定义语句组成但实际上是任意Python代码)时。

我正在使用术语"解析时间"即使技术上在转换中读取源代码时,也是对字节码的完全编译,因为C和C ++编译的语义不同,例如函数的定义在该阶段发生(而在Python中运行时发生)

即使相当于#include的C和C ++(在Python中是import)也是一个在运行时而不是在编译(解析)时执行的常规语句,因此可以放置它在常规python if内。例如,如果系统中不存在特定的可选Python库,import块内的try将为某些函数提供备用定义。

最后请注意,在Python中,您甚至可以通过使用exec从头开始在运行时创建新的函数和类,而不必在源代码中使用它们。您也可以使用代码直接组装这些对象,因为类和函数确实只是常规对象(这通常仅针对类进行)。

有些工具会尝试将defclass定义和import语句视为" static",例如对Python进行静态分析用于生成可疑片段警告或创建自包含可部署软件包的代码,该软件包不依赖于在系统上安装特定的Python来运行该程序。但是,所有这些都需要考虑到Python在这个领域比C或C ++更具动态性,并且它们还允许在自动分析失败的地方添加例外。

答案 2 :(得分:6)

这是一个我用来区分Python 2& 3我的Python Tk程序:


import sys
if sys.version_info[0] == 3:
    from tkinter import *
    from tkinter import ttk
else:
    from Tkinter import *
    import ttk

""" rest of your code """

希望这是一个有用的例子。

答案 3 :(得分:5)

据我所知,你必须使用实际的if语句。没有预处理器,因此没有类似于预处理器指令。

编辑:实际上,看起来这个问题的最佳答案会更有启发性:How would you do the equivalent of preprocessor directives in Python?

据说有一个特殊变量__debug__,当与if语句一起使用时,将被评估一次,然后在执行期间不再进行评估。

答案 4 :(得分:2)

没有我所知道的直接等效内容,因此您可能需要缩小并重新考虑使用预处理器解决的问题。

如果它只是诊断记录,那么你就会有一个全面的记录模块,它应该涵盖你想要的一切以及更多。

http://docs.python.org/library/logging.html

您还使用预处理器做什么?测试配置?有一个配置模块。

http://docs.python.org/library/configparser.html

还有别的吗?

答案 5 :(得分:0)

如果您使用#ifdef检查可能已在当前文件上方的范围中定义的变量,则可以使用例外。例如,我想要在ipython与外部ipython内运行不同的脚本(例如,显示绘图与保存图)。所以我添加

     ipy = False
     try:
        ipy = __IPYTHON__
     except NameError:
        pass

这给我留下了一个变量ipy,它告诉我__IPYTHON__是否在我当前脚本上方的范围内声明。对于Python中的#ifdef函数,这是我所知道的最接近的并行。

对于ipython,这是一个很好的解决方案。您可以在其他上下文中使用类似的构造,其中调用脚本设置变量值,内部脚本相应地进行检查。当然,这是否有意义取决于您的具体用例。

答案 6 :(得分:0)

我自己没有尝试过,但https://code.google.com/p/pypreprocessor/

怎么样

答案 7 :(得分:0)

如果您正在研究Spyder,则可能只需要以下内容:

try:
    print(x)
except:
    #code to run under ifndef
    x = "x is defined now!"
#other code

第一次运行脚本,将在#code to run under ifndef下运行代码,第二次,将跳过该代码。 希望它能工作:)

答案 8 :(得分:0)

这可以通过传递如下命令行参数来实现:

import sys

my_macro = 0

if(len(sys.argv) > 1):
    for x in sys.argv:
        if(x == "MACRO"):
            my_macro = 1

if (my_macro == 1):
    controlled text

尝试运行以下脚本,然后观察结果:

python myscript.py MACRO

希望这会有所帮助。