49

在我以前的编程中C,代码部分仅用于调试目的(记录命令等)。这些语句可以通过使用#ifdef预处理器指令完全禁用生产,如下所示:

 #ifdef MACRO

 controlled text

 #endif /* MACRO */

做类似事情的最佳方法是什么python

4

8 回答 8

37

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

如果您想在字节码编译时根据特定变量实际删除代码块,您唯一的选择是相当神秘的__debug__全局变量。True除非-O标志被传递给 Python(或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“优化”。

于 2012-09-21T05:42:53.467 回答
9

重要的是要了解在 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 的运行时)。

甚至相当于#includeC 和 C++(在 Python 中是import)的等价物是在运行时而不是在编译(解析)时执行的常规语句,因此它可以放在常规 pythonif中。很常见的是,例如,如果系统上不存在特定的可选 Python 库,则import在一个try块内部将为某些函数提供替代定义。

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

有一些工具会尝试将定义和def语句视为“静态”,例如对 Python 代码进行静态分析以在可疑片段上生成警告或创建不依赖于系统上的特定 Python 安装以运行程序。然而,所有这些都需要能够考虑到 Python 在这方面比 C 或 C++ 更具动态性,并且它们还允许为自动分析失败的地方添加异常。classimport

于 2012-09-21T05:46:15.027 回答
9

这是我用来区分 Python Tk 程序的 Python 2 和 3 的示例:

导入系统
如果 sys.version_info[0] == 3:
    从 tkinter 导入 *
    从 tkinter 导入 ttk
别的:
    从 Tkinter 导入 *
    导入ttk

""" 其余代码 """

希望这是一个有用的说明。

于 2016-04-06T21:23:59.100 回答
7

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

编辑:实际上,看起来这个问题的最佳答案会更有启发性:你将如何在 Python 中执行相当于预处理器指令的操作?

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

于 2012-09-21T05:11:22.440 回答
2

我知道没有直接的等价物,因此您可能想要缩小并重新考虑您过去使用预处理器解决的问题。

如果它只是您所追求的诊断日志记录,那么有一个全面的日志记录模块应该涵盖您想要的所有内容以及更多内容。

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

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

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

还要别的吗?

于 2012-09-21T05:25:44.817 回答
0

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

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

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

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

于 2015-06-07T11:48:43.443 回答
-1

如果你正在使用 Spyder,你可能只需要这个:

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

第一次,你运行你的脚本,你会运行下面的代码#code to run under ifndef,第二次,你会跳过它。希望它有效:)

于 2019-04-19T16:46:26.200 回答
-1

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

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

希望这可以帮助。

于 2019-08-23T03:13:05.877 回答