35

以下のコードで参照する場所で、次のコードをその場で呼び出したいと思いMY_MACROます。

# MY_MACRO
frameinfo = getframeinfo(currentframe())
msg = 'We are on file ' + frameinfo.filename + ' and line ' +  str(frameinfo.lineno)
# Assumes access to namespace and the variables in which `MY_MACRO` is called. 
current_state = locals().items()

を使用するコードを次に示しますMY_MACRO

def some_function:
    MY_MACRO

def some_other_function:
    some_function()
    MY_MACRO

class some_class:
  def some_method:
     MY_MACRO

それが役立つ場合:

  1. MY_MACROこの機能が必要な理由の 1 つは、必要な場所でコードを繰り返すことを避けたいからです。短くて簡単なものがあると非常に役立ちます。
  2. もう 1 つの理由は、マクロ内に IPython シェルを埋め込み、すべての変数にアクセスできるようにしたいからですlocals().items()(この他の質問を参照してください) 。

これはPythonでまったく可能ですか? これを機能させる最も簡単な方法は何ですか?

マクロは、それが呼び出されたスコープの名前空間全体へのアクセスを想定していることに注意してください(つまり、単にコードを関数に配置するだけでは機能しません)。関数に配置すると、間違った行番号が出力されることにも注意してください。MY_MACROMY_MACROlineno

4

7 に答える 7

27

MacroPyは、Python に構文マクロを導入する私のプロジェクトです。このプロジェクトはまだ 3 週間しか経っていませんが、リンクを見ると、非常にクールなデモのコレクションがあり、それを使用して必要な機能を確実に実装できることがわかります。

一方、python には非常に驚くべきイントロスペクション機能がいくつかあるので、その機能を純粋に使用して目的を達成できるのではないかと思います。

于 2013-05-11T04:10:38.453 に答える
17

あなたが呼び出すことができる関数はどうですか?この関数は呼び出し元のフレームにアクセスし、 を使用するのではなく、 をlocals()使用frame.f_localsして呼び出し元の名前空間を取得します。

def my_function():
    frame = currentframe().f_back
    msg = 'We are on file {0.f_code.co_filename} and line {0.f_lineno}'.format(frame)
    current_state = frame.f_locals
    print current_state['some_variable']

次に、それを呼び出します:

def some_function:
    my_function()

def some_other_function:
    some_function()
    my_function()

class some_class:
  def some_method:
     my_function()
于 2013-03-27T21:34:33.627 に答える
2

デバッグに必要だったように、呼び出し元の行と関数名だけが必要な場合は、 inspect.getouterframes linkで呼び出し元の関数情報を取得できます。

import inspect
def printDebugInfo():
  (frame,filename,line_number,function_name, lines, 
    index) = inspect.getouterframes(inspect.currentframe())[1]
  print(filename, line_number, function_name, lines, index)

def f1():
  printDebugInfo()

if __name__=='__main__':
  f1()
于 2016-06-03T08:46:49.117 に答える
2

これが良い解決策かどうかはわかりませんが、少なくともマクロ プリプロセッサを検討する価値はあります。

いくつかの異なる拡張 Python with マクロ プロジェクト、またはそのようなことをより簡単にする広範なプロジェクトがありますが、それらすべて (Logix、MetaPython、Mython、Espy) の期限切れのリンクしかありません…現在のリンクおよび/またはより新しい/肝臓のプロジェクトを探す価値があります。

m4またはのようなcppもの、またはより強力なものを使用することも、自分で構築することもできます。しかし、実際には、純粋なテキスト マクロの小さな静的セット (これまでのところ 1 つ) を取得しただけです。最悪の場合、インデント レベルを検出しMY_MACRO、それを各行の先頭に追加する必要があります。これは、正規表現で行うのは簡単です。つまりsed、または 3 行の Python スクリプトをプリプロセッサにすることができます。

ただし、2 つの問題、または少なくとも煩わしさがあります。

まず、ファイルを前処理する必要があります。setup.pyC 拡張モジュール、生成されたコード、または実行する前に必要なその他のコードを既に使用している場合、makeまたはsconscmd-R または ctrl-shift を押すだけの IDE を使用している場合-B またはコードをテストするものは何でも、これは問題ではありません。しかし、1 つのウィンドウにテキスト エディターがあり、別のウィンドウに対話型インタープリターがある典型的な編集-テスト ループの場合は、それを編集-コンパイル-テスト ループに変えただけです。うーん。私が考えることができる唯一の解決策は、モジュールとしてインポートする前にすべてのファイルを前処理するインポート フックです。

次に、行番号とソース (MY_MACROそれ自体やトレースバックなどからinspect.getsource) は、編集用に開いた元のソースではなく、前処理されたファイルの行番号になります。あなたの前処理されたファイルはかなり読みやすいので、それはひどいことではありません(ほとんどの CoffeeScript コミュニティが毎日行っている、CoffeeScript をコーディングして JavaScript としてデバッグするほど悪くはありません…) が、それは間違いなく面倒です。

もちろん、これを解決する 1 つの方法は、解析/コンパイル プロセスの任意の段階で、独自のマクロ プロセッサをインタプリタに組み込むことです。それはあなたがやりたいことよりもはるかに多くの作業だと思いますが、そうする場合 Guido は常に、「ねえ、追加しましょう」という漠然とした提案を拒否し続けるよりも、実際に機能する設計と実装を拒否することを好みますマクロを Python に". :)

于 2013-03-27T23:39:30.943 に答える
1

次の場合は、関数を使用できます。

def MY_MACRO():
    frame = currentframe()
    try:
        macro_caller_locals = frame.f_back.f_locals
        print(macro_caller_locals['a'])

    finally:
        del frame

def some_function:
    a = 1
    MY_MACRO()
于 2013-03-27T21:35:04.363 に答える
0

Python にはマクロがないため、これを行う関数を定義する必要があります。現在のスタック フレームをキャプチャしたいようですがcurrentframe()、呼び出しサイトから共有関数に渡すことで簡素化できます。地元の人と同上。

def print_frame_info(frameinfo, locals):
    msg = 'We are on file ' + frameinfo.filename + ' and line ' +  str(frameinfo.lineno)
    current_state = locals.items()

def some_other_function:
    some_function()
    print_frame_info(currentframe(), locals())
于 2013-03-27T21:39:19.493 に答える