向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
的代码。简单明了的东西会很有帮助李>
locals().items()
(请参阅)请注意宏假定可以访问调用它的作用域的整个名称空间(即仅将代码
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()