给定框架对象(例如,由sys._getframe返回),我可以获取底层可调用对象吗?
代码说明:
def foo():
frame = sys._getframe()
x = some_magic(frame)
# x is foo, now
请注意,我的问题是将对象从框架中取出,而不是当前调用的对象。
希望这是可能的。
干杯,
MH
修改
我有点设法解决这个问题。安德烈亚斯和亚历山大的回复深受启发。谢谢各位投入的时间!
def magic():
fr = sys._getframe(1)
for o in gc.get_objects():
if inspect.isfunction(o) and o.func_code is fr.f_code:
return o
class Foo(object):
def bar(self):
return magic()
x = Foo().bar()
assert x is Foo.bar.im_func
(适用于2.6.2,py3k替换func_code
__code__
和im_func
__func__
然后,我可以积极遍历globals()或gc.get_objects()和dir()所有内容,以搜索具有给定函数对象的callable。
对我来说感觉有点不熟悉,但是有效。
再次感谢!
MH
答案 0 :(得分:1)
为了支持所有情况,包括函数是类的一部分或只是一个全局函数,没有直接的方法来做到这一点。您可能能够获得完整的调用堆栈并在globals()
中向下迭代,但这不会很好......
我能得到的最接近的是:
import sys, types
def magic():
# Get the frame before the current one (i.e. frame of caller)
frame = sys._getframe(1)
# Default values and closure is lost here (because they belong to the
# function object.)
return types.FunctionType(frame.f_code, frame.f_globals)
class MyClass(object):
def foo(self, bar='Hello World!'):
print bar
return magic()
test = MyClass()
new_foo = test.foo()
new_foo(test, 'Good Bye World!')
您将执行完全相同的代码,但它将在新的代码包装器中(例如,FunctionType
。)
我怀疑你希望能够根据堆栈恢复你的应用程序的状态...这里至少会调用函数尽可能地与原始调用相似(闭包仍然被遗漏,因为如果你可以从帧中获得闭包,获得被调用的函数将非常简单):
import sys, types
class MyClass(object):
def __init__(self, temp):
self.temp = temp
def foo(self, bar):
print self.temp, bar
return sys._getframe()
def test(hello):
print hello, 'World!'
return sys._getframe()
def recall(frame):
code = frame.f_code
fn = types.FunctionType(
code, frame.f_globals, code.co_name,
# This is one BIG assumption that arguments are always last.
tuple(frame.f_locals.values()[-code.co_argcount:]))
return fn()
test1 = MyClass('test1')
frame1 = test1.foo('Hello World!')
test2 = MyClass('test2')
frame2 = test2.foo('Good Bye World!')
frame3 = test2.foo('Sayonara!')
frame4 = test('HI')
print '-'
recall(frame4)
recall(frame3)
recall(frame2)
recall(frame1)
答案 1 :(得分:1)
有点难看,但现在是:
frame.f_globals[frame.f_code.co_name]
完整示例:
#!/usr/bin/env python
import sys
def foo():
frame = sys._getframe()
x = frame.f_globals[frame.f_code.co_name]
print foo is x
foo()
打印'真'。
答案 2 :(得分:0)
不是答案,而是评论。我将其添加为评论,但我没有足够的"声誉点"。
对于它的价值,这是一个合理的(我认为)用例,想要做这类事情。
我的应用程序使用gtk,并旋转了很多线程。任何人都知道这两个人都做了,你就无法触及主线程之外的GUI。一个典型的解决方法是将将触及GUI的调用程序传递给idle_add()
,稍后将在主线程中运行它,这是安全的。所以我有一个很多的出现次数:
def threaded_gui_func(self, arg1, arg2):
if threading.currentThread().name != 'MainThread':
gobject.idle_add(self.threaded_gui_func, arg1, arg2)
return
# code that touches the GUI
如果我能做的话,它会更短更容易(并且更有利于切割粘贴)
def thread_gui_func(self, arg1, arg2):
if idleIfNotMain(): return
# code that touches the GUI
其中idleIfNotMain()如果我们在主线程中,则返回False,但如果不是,则使用inspect(或其他)来计算可调用和args以传递给idle_add()
,然后返回True。获得我能弄明白的args。获得可调用性似乎并不太容易。 : - (