基本上我想做这样的事情: How can I hook a function in a python module?
但是我想在我自己的代码之后调用旧函数。
像
import whatever
oldfunc = whatever.this_is_a_function
def this_is_a_function(parameter):
#my own code here
# and call original function back
oldfunc(parameter)
whatever.this_is_a_function = this_is_a_function
这可能吗?
我尝试了copy.copy
,copy.deepcopy
原始功能,但它无效。
答案 0 :(得分:6)
这样的东西?它避免使用全局变量,这通常是一件好事。
import whatever
import functools
def prefix_function(function, prefunction):
@functools.wraps(function)
def run(*args, **kwargs):
prefunction(*args, **kwargs)
return function(*args, **kwargs)
return run
def this_is_a_function(parameter):
pass # Your own code here that will be run before
whatever.this_is_a_function = prefix_function(
whatever.this_is_a_function, this_is_a_function)
prefix_function
是一个带有两个函数的函数:function
和prefunction
。它返回一个接受任何参数的函数,并使用相同的参数调用prefunction
后跟function
。 prefix_function
函数适用于任何可调用函数,因此您只需要为前缀代码编程一次,以便进行任何其他可能的挂钩操作。
@functools.wraps
使得返回的包装函数的docstring和name是相同的。
如果您需要this_is_a_function
使用不同于传递给它的参数调用旧whatever.this_is_a_function
,您可以执行以下操作:
import whatever
import functools
def wrap_function(oldfunction, newfunction):
@functools.wraps(function)
def run(*args, **kwargs):
return newfunction(oldfunction, *args, **kwargs)
return run
def this_is_a_function(oldfunc, parameter):
# Do some processing or something to customize the parameters to pass
newparams = parameter * 2 # Example of a change to newparams
return oldfunc(newparams)
whatever.this_is_a_function = wrap_function(
whatever.this_is_a_function, this_is_a_function)
如果whatever
是纯C模块,则存在一个问题,即首先改变其内部结构通常是不可能的(或非常困难)。
答案 1 :(得分:2)
所以,这是一个从time
模块中修补time
函数的示例。
import time
old_time = time.time
def time():
print('It is today... but more specifically the time is:')
return old_time()
time.time = time
print time.time()
# Output:
# It is today... but more specifically the time is:
# 1456954003.2
但是,如果您尝试对C代码执行此操作,则很可能会收到类似cannot overwrite attribute
的错误。在这种情况下,您可能希望子类化C模块。
您可能需要查看this question。
答案 2 :(得分:2)
这是吹捧我超级简单的胡克的最佳时机
def hook(hookfunc, oldfunc):
def foo(*args, **kwargs):
hookfunc(*args, **kwargs)
return oldfunc(*args, **kwargs)
return foo
难以置信的简单。它将返回一个首先运行所需钩子函数的函数(具有相同的参数,请注意),然后运行您正在挂钩的原始函数并返回该原始值。这也可以覆盖类方法。假设我们在类中有静态方法。
class Foo:
@staticmethod
def bar(data):
for datum in data:
print(datum, end="") # assuming python3 for this
print()
但是我们想在打印出元素之前打印数据的长度
def myNewFunction(data):
print("The length is {}.".format(len(data)))
现在我们简单地挂钩函数
Foo.bar(["a", "b", "c"])
# => a b c
Foo.bar = hook(Foo.bar, myNewFunction)
Foo.bar(["x", "y", "z"])
# => The length is 3.
# => x y z
答案 3 :(得分:0)
实际上,您可以替换目标函数func_code
。以下示例
# a normal function
def old_func():
print "i am old"
# a class method
class A(object):
def old_method(self):
print "i am old_method"
# a closure function
def make_closure(freevar1, freevar2):
def wrapper():
print "i am old_clofunc, freevars:", freevar1, freevar2
return wrapper
old_clofunc = make_closure('fv1', 'fv2')
# ===============================================
# the new function
def new_func(*args):
print "i am new, args:", args
# the new closure function
def make_closure2(freevar1, freevar2):
def wrapper():
print "i am new_clofunc, freevars:", freevar1, freevar2
return wrapper
new_clofunc = make_closure2('fv1', 'fv2')
# ===============================================
# hook normal function
old_func.func_code = new_func.func_code
# hook class method
A.old_method.im_func.func_code = new_func.func_code
# hook closure function
# Note: the closure function's `co_freevars` count should be equal
old_clofunc.func_code = new_clofunc.func_code
# ===============================================
# call the old
old_func()
A().old_method()
old_clofunc()
输出:
i am new, args: ()
i am new, args: (<__main__.A object at 0x0000000004A5AC50>,)
i am new_clofunc, freevars: fv1 fv2