這裏做的一種方式,創造了新富由黑客函數內部是「做正確的事」。 (正如@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