这里做的一种方式,创造了新富由黑客函数内部是“做正确的事”。 (正如@DSM所提到的)。不幸的是,我们无法跳入foo
函数,并且因为它们的内部大部分被标记为只读,所以我们必须做的是修改我们手工构建的副本。
我很确定它不会去捕捉所有情况。但是,它的工作原理的例子(我在一个旧的Python 2.5.1)
丑女位,可能与一些整理是做:
- 巨大的参数列表传递给CODETYPE
- 的从
co_consts
构建的丑陋元组只覆盖一个成员。所有的信息都在co_consts中以确定要替换哪个 - 所以更聪明的功能可以做到这一点。我使用print(foo.func_code.co_consts)
手工挖入内部。
您可以通过使用解释 命令help(types.CodeType)
找到有关CodeType
和FunctionType
一些信息。
更新: 我认为这太丑了,所以我建立了一个辅助函数,使它更漂亮。有了助手,你可以写:
# Use our function to get a new version of foo with "bar" replaced by mybar
foo = monkey_patch_fn(foo, "bar", my_bar)
# Check it works
foo()
这里是monkey_patch_fn
实现:
# Returns a copy of original_fn with its internal function
# called name replaced with new_fn.
def monkey_patch_fn(original_fn, name, new_fn):
#Little helper function to pick out the correct constant
def fix_consts(x):
if x==None: return None
try:
if x.co_name == name:
return new_fn.func_code
except AttributeError, e:
pass
return x
original_code = original_fn.func_code
new_consts = tuple(map(fix_consts, original_code.co_consts))
code_type_args = [
"co_argcount", "co_nlocals", "co_stacksize", "co_flags", "co_code",
"co_consts", "co_names", "co_varnames", "co_filename", "co_name",
"co_firstlineno", "co_lnotab", "co_freevars", "co_cellvars" ]
new_code = types.CodeType(
*[ (getattr(original_code,x) if x!="co_consts" else new_consts)
for x in code_type_args ])
return types.FunctionType(new_code, {})
当使用'bar'?它是否在后面的函数中使用(比如'baz'?)在这种情况下,你会*想要替换它,对吧?确切地说, – 2012-08-11 03:21:36
。任何方式来做到这一点? – Paolo 2012-08-11 03:24:38
您可以访问函数的各种内部细节,因为它们只是对象。使用dir函数和语言参考了解更多信息。 – Marcin 2012-08-11 03:48:31