jpc*_*cgt 5 python bytecode introspection
我需要在运行时更改对另一个函数内的函数的调用.
请考虑以下代码:
def now():
print "Hello World!"
class Sim:
def __init__(self, arg, msg):
self.msg = msg
self.func = arg
self.patch(self.func)
def now(self):
print self.msg
def run(self):
self.func()
def patch(self, func):
# Any references to the global now() in func
# are replaced with the self.now() method.
def myfunc():
now()
Run Code Online (Sandbox Code Playgroud)
然后 ...
>>> a = Sim(myfunc, "Hello Locals #1")
>>> b = Sim(myfunc, "Hello Locals #2")
>>> b.run()
Hello Locals #2
>>> a.run()
Hello Locals #1
Run Code Online (Sandbox Code Playgroud)
一个用户编写代码,myfunc()调用全局定义的函数now(),我无法编辑它.但我想让它调用Sim实例的方法.所以我需要myfunc()在运行时"修补"该功能.
我怎么能这样做?
一种可能的解决方案是编辑字节码,如下所示:http://web.archive.org/web/20140306210310/http: //www.jonathon-vogel.com/posts/patching_function_bytecode_with_python但我想知道是否有更方便.
这比看起来更棘手。为此,您需要:
使用方法创建一个dict子类__missing__来保存新值now。然后该__missing__方法从通常的字典中获取字典中没有的任何项目globals()。
从现有myfunc()函数创建一个新函数对象,保留其代码对象,但使用为全局变量创建的新字典。
使用新函数的函数名称将新函数分配回全局变量。
就是这样:
def now():
print "Hello World!"
class NowGlobals(dict):
def __init__(self, now, globals):
self["now"] = now
self.globals = globals
def __missing__(self, key):
return self.globals[key]
class Sim(object):
def __init__(self, func):
func = self.patch(func)
self.func = func
def now(self):
print "Hello locals!"
def patch(self, func):
funcname = func.__name__
nowglobals = NowGlobals(self.now, func.func_globals)
func = type(func)(func.func_code, nowglobals)
globals()[funcname] = func
return func
def myfunc():
now()
sim = Sim(myfunc)
myfunc()
Run Code Online (Sandbox Code Playgroud)
确实没有必要在课堂上使用它,但我一直保持这种方式,因为这就是你最初编写它的方式。
如果myfunc在另一个模块中,您需要重写Sim.patch()以修补回该名称空间,例如module.myfunc = sim.patch(module.myfunc)
| 归档时间: |
|
| 查看次数: |
596 次 |
| 最近记录: |