Python 2.5有类似于Tcl的uplevel命令的等效命令吗?

3

Python有没有与Tcl的uplevel命令相当的功能?对于那些不知道的人来说,“uplevel”命令可以让您在调用者的上下文中运行代码。以下是在Python中实现此功能的示例:

def foo():
    answer = 0
    print "answer is", answer # should print 0
    bar()
    print "answer is", answer # should print 42


def bar():
    uplevel("answer = 42")

然而,这不仅仅是设置变量,因此我不希望仅仅修改字典的解决方案。我想能够执行任何代码。


1
有一些不好的方法可以做到这一点,但也许您可以描述一下您的原始问题,这样我们就可以找到更符合Python风格的解决方案? - Michał Kwiatkowski
@Bryan Oakley:你可能需要尝试一下堆栈帧等相关内容。我对此了解不够,无法提供帮助,但这可能会指引你朝正确的方向前进。 - Daenyth
def uplevel(var, val): inspect.getouterframes(inspect.currentframe())[2][0].f_locals[var]=val 无效。 - Sharun
如果它允许在调用堆栈的任何位置执行任意代码,我会非常惊讶它是否可以被模拟。当然,这只限于同一个解释器内部;它不能跨越安全分区。当然,大多数代码并不以这种方式使用它,但它是一个异常强大的机制。 - Donal Fellows
@Donald Fellows:是的,我可能每两三年才会使用一次uplevel。但当我使用它时,它就是救星。我希望Python有等效的功能。显然没有。那就换计划吧。 - Bryan Oakley
显示剩余3条评论
2个回答

3
总的来说,你所要求的(根据你的期望结果)是不可能实现的。例如,想象一下“任何代码”是x = 23。假设你找到了一个黑魔法的方法,在“调用者”中执行这段代码,那么它会将新变量x添加到调用者的本地变量集合中吗?不会--Python编译器执行的关键优化是在def执行时定义一次性确切的本地变量集合(所有在函数体中分配或绑定的裸名),并将对这些裸名的每个访问和设置转换为非常快速的索引进入堆栈帧。(你可以通过在每个可能的调用者开头使用exec ''系统地打败这个关键优化——并看到你的系统性能因此崩溃)。
除了分配给调用者的本地裸名之外,exec thecode in thelocals, theglobals可能会大致实现你想要的功能,而inspect模块允许您以半合理的方式获取调用者的本地和全局变量(就深度黑魔法而言——如果有人建议在生产代码中实施它,我会发疯的称赞它“半合理”,也就毫不值得称赞了)。
但你确实指定了“我想能够执行任何代码。”而对于那个明确的规范(感谢你如此精确,因为这使得回答更容易!),唯一的解决方案是:使用不同的编程语言。

修改本地变量确实不可能,至少不是在不进入 C 级别的情况下。让我添加这两个链接以供进一步阅读:http://bugs.python.org/issue1654367 和 http://mail.python.org/pipermail/python-dev/2007-February/070885.html - Michał Kwiatkowski
2
这个答案在我看来有点说教,不是很有用。 - Bryan Oakley
1
@Bryan,你有权发表自己的意见,当然可以表达出来,但我同样有权强烈反对——并且绝对厌恶你的行为,总结如下:你声称想运行任何代码;我向你明确展示了你不能这样做的原因;你发布了一个自问自答的帖子(这本身就是可疑的做法),而且不符合你自己的要求,而不是感谢我阻止你浪费时间去尝试其他方法,反而批评和踩我。适当的非说教式反应需要暴力,物理或至少言语上的,所以我宁愿说教。 - Alex Martelli
回答自己的问题是否可疑?SO难道没有这方面的徽章吗?我认为FAQ中也提到了这是可以的。至于它没有回答我的原始问题,你是对的。如果我能够创建一个完全可行的答案,我会这样做,但我不能。我发布了我所拥有的并询问是否有人可以改进它。至于感谢你阻止我浪费时间..?我的时间并没有浪费;我学到了一些东西。而你怎么知道是我给你投了反对票?有人赞同了我的评论,所以不喜欢你的回答的不只有我一个人。 - Bryan Oakley
我没有给你的答案点赞,因为说实话,我不确定它是否权威或正确。就像我说的,它有点说教,让我对答案有些不信任。我只需要事实,而不是意见。 - Bryan Oakley

1

这个第三方库是用Python编写的吗?如果是,你可以在运行时重写和重新绑定函数“foo”以使用自己的实现。像这样:

import third_party

original_foo = third_party.foo
def my_foo(*args, **kwds):
    # do your magic...
    original_foo(*args, **kwds)
third_party.foo = my_foo

我猜猴子补丁比重写框架局部变量略好一些。 ;)


是的,它是用Python编写的。不过,我不是在寻找Monkeypatching解决方案。 - Bryan Oakley
1
正如Alex向您解释的那样,由于CPython的实现方式,您不会找到编写“uplevel”的方法。您需要以不同的方式来解决这个问题。 - Michał Kwiatkowski
Kwiatkowski:谢谢,但我不是在寻找解决方案,我正在寻找答案,即“Python是否具有类似uplevel的功能?”使用类似uplevel的功能是我正在考虑的几种可能解决方案之一。我不是新手,要求你为我完成工作,我只是试图收集有关我尚未深入了解的语言的事实。 - Bryan Oakley
好的,所以你问题的答案是“在纯Python中不行”,详细信息请参考Alex的回答。如果需要更多细节,您需要深入研究CPython源代码,这相当容易阅读。我猜您可以在C级别(或使用ctypes)上进行一些邪恶的操作,但本地访问是低级实现细节。例如,优化解释器可以内联本地变量,因此没有剩余内容可分配。最好不要依赖它们的存在。 - Michał Kwiatkowski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接