web-dev-qa-db-ja.com

Pythonで「#ifdef」をどのように実装しますか?

Cでのプログラミング以前は、デバッグ目的(コマンドのロギングなど)にのみコードセクションを使用していました。これらのステートメントは、#ifdef次のようなプリプロセッサディレクティブ:

 #ifdef MACRO

 controlled text

 #endif /* MACRO */

pythonで似たようなことをする最良の方法は何ですか?

32
dangonfast

ロギングメソッドを無効にするだけの場合は、loggingモジュールを使用します。ログレベルがデバッグステートメントなどを除外するように設定されている場合、logging.debugはno-opに非常に近くなります(ログレベルをチェックし、ログ文字列を補間せずに戻ります)。

特定の変数を条件として、バイトコードのコンパイル時にコードのチャンクを実際に削除したい場合、唯一のオプションはかなり謎めいた__debug__グローバル変数です。この変数は、-OフラグがPythonに渡される場合(またはTrueが環境内で空でないものに設定される場合)を除き、PYTHONOPTIMIZEに設定されます。

__debug__ifステートメントで使用されている場合、ifステートメントは実際にはTrueブランチのみにコンパイルされます。この特定の最適化は、Pythonこれまでのようにプリプロセッサマクロに近いものです。

マクロとは異なり、ifの両方のブランチでコードが構文的に正しい必要があることに注意してください。


__debug__がどのように機能するかを示すために、次の2つの関数を検討してください。

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のみです。

27
nneonneo

Python 2&3 for my Python= Tkプログラムを区別するために使用する例を示します。

 
 import sys 
 if sys.version_info [0] == 3:
 from tkinter import * 
 from tkinter import ttk 
 else:
 from Tkinter import * 
 import ttk 
 
 "" "残りのコード" "" 

それが有用な例であることを願っています。

7
Richard

In Python defclassは2つの通常の実行可能ステートメントであることを理解することが重要です...

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++と根本的に異なります。「コンパイル時間」という概念が存在せず、2つのフェーズが「解析時間」(ソースコードの読み込み時)と解析されたコードの「実行時」 (通常は主に定義ステートメントで構成されますが、実際には任意のPythonコード)が実行されます。

CとC++のコンパイルのセマンティクスが異なり、たとえば関数の定義がその段階で行われるため、技術的に変換でソースコードが読み取られるときにバイトコードへの完全なコンパイルである場合でも、用語「解析時間」を使用しています代わりに、Pythonの実行時に発生します)。

CおよびC++の#include(Pythonのimportは)に相当)は、コンパイルではなく実行時に実行される通常のステートメントです(解析します) )通常のpython if。内に配置できるようになります。たとえば、importブロック内にtry特定のオプションのPythonライブラリがシステムに存在しない場合、一部の関数の代替定義を提供します。

最後に、Pythonでは、ソースコードに必ずしもそれらを含める必要はありませんが、execを使用して、実行時に新しい関数やクラスを最初から作成することもできます。クラスと関数は実際には単なる通常のオブジェクトであるため、コードを直接使用するこれらのオブジェクト(これは通常、クラスに対してのみ行われます)。

代わりにdefおよびclassの定義とimportステートメントを「静的」と見なそうとするツールがいくつかあります。たとえば、Python不審なフラグメントに関する警告を生成するコード、または特定のPythonプログラムを実行するシステムへのインストールに依存しない自己完結型の展開可能なパッケージを作成するコード。ただし、この領域ではPythonはCまたはC++よりも動的であり、自動分析が失敗する場所に例外を追加できることを考慮する必要があります。

6
6502

私の知る限り、実際のifステートメントを使用する必要があります。プリプロセッサがないため、プリプロセッサディレクティブに類似するものはありません。

編集:実際には、この質問の一番上の答えがより明らかになるように見えます: Pythonでプリプロセッサディレクティブに相当する方法は何ですか?

特別な変数__debug__があり、ifステートメントと一緒に使用すると、一度評価された後、実行中に再度評価されることはありません。

5

私が知っている直接的な同等物はないので、ズームアウトして、プリプロセッサを使用して解決するために使用した問題を再検討することができます。

診断ログだけの場合は、必要なものすべてをカバーする包括的なログモジュールがあります。

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

他に何をプリプロセッサを使用しますか?テスト構成?そのための設定モジュールがあります。

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

他に何か?

2
John Mee

#ifdefを使用して、現在のファイルの上のスコープで定義されている可能性のある変数をチェックしている場合、例外を使用できます。たとえば、ipythonipythonの外部(たとえば、プロットを表示するかプロットを保存するか)から異なる方法で実行したいスクリプトがあります。だから私は追加します

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

これにより、変数ipyが残ります。この変数は、__IPYTHON__が現在のスクリプトの上のスコープで宣言されたかどうかを示します。これは、Pythonの#ifdef関数について知っている最も近い並列です。

ipythonの場合、これは優れたソリューションです。他のコンテキストでも同様の構成を使用できます。この場合、呼び出し元のスクリプトが変数値を設定し、それに応じて内部スクリプトがチェックします。もちろん、これが理にかなっているかどうかは、特定のユースケースに依存します。

0
mmdanziger

Spyderで作業している場合、おそらくこれだけが必要です:

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

最初にスクリプトを実行すると、#code to run under ifndefの下でコードが実行され、2回目はスキップします。うまくいくことを願っています:)

0
Yanqi Huang

私は自分で試したことはありませんが、どうですか https://code.google.com/p/pypreprocessor/

0
Mark Lawrence

これは、次のようにコマンドライン引数を渡すことで実現できます。

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

お役に立てれば。

0
DesiKeki