向Python添加宏

向Python添加宏,python,macropy,Python,Macropy,我想在我下面的代码中引用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. c

我想在我下面的代码中引用
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_宏的代码:

def some_function:
    MY_MACRO

def some_other_function:
    some_function()
    MY_MACRO

class some_class:
  def some_method:
     MY_MACRO
如果有帮助:

  • 我希望拥有此功能的原因之一是,我希望避免在需要时重复
    MY_MACRO
    的代码。简单明了的东西会很有帮助
  • 另一个原因是我想在宏中嵌入一个IPython shell,并且我想访问
    locals().items()
    (请参阅)
  • 这在Python中是可能的吗?最简单的方法是什么


    注意宏假定可以访问调用它的作用域的整个名称空间(即仅将代码
    MY_宏
    放在函数中将不起作用)。另请注意,如果我将
    我的\u宏
    放入函数中,
    行号
    将输出错误的行号。

    您可以调用的函数如何?此函数访问调用方的帧,而不是使用
    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()
    

    如果您想:

    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()
    

    我认为应该定义一个函数来实现这一点,因为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())
    

    我不确定这是否是一个好的解决方案,但至少值得考虑使用宏预处理器

    有几个不同的带有宏的extend Python项目,或者更广泛的项目,它们应该使这样的事情更容易完成,但是我只有所有这些项目的过期链接(Logix、MetaPython、Mython、Espy)…可能值得寻找当前的链接和/或更新的/或更新的项目

    您可以使用类似于
    m4
    cpp
    或更强大的功能,甚至可以自己构建一个。但实际上,您只得到了一个小的、静态的纯文本宏集(到目前为止,只有一个)。在最坏的情况下,您必须检测
    MY_MACRO
    的缩进级别,并将其添加到每行的开头,这在正则表达式中很容易做到。意思是说,
    sed
    或3行Python脚本可以作为预处理器

    然而,有两个问题,或者至少是烦恼

    首先,您需要预处理文件。如果您已经在使用C扩展模块或生成的代码或任何其他需要您在运行它之前进行
    setup.py
    (或
    make
    scons
    或其他任何操作)的代码,或者您正在使用只需点击cmd-R或ctrl-shift-B或其他任何操作来测试代码的IDE,那么这不是问题。但是对于典型的编辑测试循环,在一个窗口中有一个文本编辑器,在另一个窗口中有一个交互式解释器……好吧,您刚刚将其转换为编辑编译测试循环。啊。我能想到的唯一解决方案是一个导入钩子,它在将每个文件作为模块导入之前对其进行预处理,这似乎是为了一个小小的好处而做的大量工作

    其次,行号和源代码(来自
    MY_MACRO
    本身,以及来自回溯和
    inspect.getsource
    等)将是预处理文件的行号,而不是您打开进行编辑的原始源代码。由于预处理的文件可读性很好,所以这并不可怕(不像编写CoffeeScript并将其作为JavaScript进行调试那样糟糕,而大多数CoffeeScript社区每天都这样做……),但这绝对是一件麻烦事

    当然,解决这个问题的一种方法是在解释器中构建自己的宏处理器,在解析/编译过程中的任何阶段。我猜这比你想做的工作要多得多,但是如果你想做的话,那么Guido总是喜欢拒绝一个实际的工作设计和实现,而不是一直拒绝“嘿,让我们向Python添加宏”之类的模糊建议:)

    是我的一个项目,它将语法宏引入Python。这个项目只有3周的历史,但是如果你看看链接,你会发现我们有一个非常酷的演示集合,你想要的功能肯定可以用它来实现


    另一方面,python有一些非常惊人的内省功能,因此我怀疑您可能能够完全使用该功能来完成您想要的任务。

    不赞成使用
    exec
    ,但它应该在这里做到这一点。例如,以以下宏为例:

    MY_MACRO = """
    print foo            
    """
    
    并使用以下代码运行它:

    foo = "breaking the rules"
    exec MY_MACRO in globals(),locals() 
    

    始终要小心使用
    exec
    ,因为它可以提供并打开代码注入的机会。

    如果您只需要调用者的行和函数名,就像调试所需的那样,您可以通过inspect.getouterframes获取调用者函数信息


    嗯,你为什么不定义一个函数呢?@delnan请阅读OP中的
    NOTE
    。如果你想处理这些帧,你可以向上移动一帧(或者任意数量的帧)以到达调用方的作用域。这是假设你确实有一个很好的理由去摆弄这些框架。还有一些跟踪函数(请参阅文档),它们可以减少攻击性。如果他使用一个函数,他必须显式地将locals()传递给该函数。我认为exec还要求显式地传递局部变量。。。宏与函数具有相同的名称和“调用”mehcanics将是一件好事,用于优化和错误检查。例如,假设我们有一个宏:@macro def myopen(filename):如果isinstance(filename,symbol)或else open(filename),则返回[open,filename]嗯,
    current\u state
    会保存调用
    MY\u宏的名称空间的变量吗?据我所知,
    locals()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()