包装一个用 import * 导入的函数?
Wrapping a function imported with import *?
我有一组测试包装了特定模块的一些功能,假设它看起来像这样:
alpha.py
def foo():
return 'foo'
def bar():
return foo(), 'bar'
debug_alpha.py
from alpha import *
def _wrapper(func):
def call(*args, **kwargs):
print('entering')
result = func(*args, **kwargs)
print('exiting')
return result
return call
def _wrapFunc(module, func):
module.__dict__[func.__name__] = _wrapper(func)
test.py
import debug_alpha
debug_alpha._wrapFunc(debug_alpha, debug_alpha.foo)
print(debug_alpha.foo())
print(debug_alpha.bar())
当然输出只有:
entering
exiting
foo
('foo', 'bar')
因为虽然 foo
函数可能已被包装 - bar
仍然引用原始 alpha
模块中的 foo
函数。是否有一种技巧可以将 foo
包装成 bar
也将在不更改导入模式的情况下调用适当的 foo
?
如果你想要 bar
调用包装的 foo
,你必须 替换 foo
在你的 alpha
模块中通过分配包装函数:alpha.foo = _wrapper(alpha.foo)
(或像在 _wrapFunc
中那样更新 alpha.__dict__
)。
在Python中,代码是数据,程序"symbols"与普通变量没有区别。每当 bar
中的代码即将调用 foo
时,Python 解释器将查找 foo
的定义,无论它位于 that[=30] =]时刻.
请注意,执行此类操作会在运行时更改您的程序,使其行为方式在源代码中并不明显。该技术称为 monkey patching(WP 文章有关于如果不小心操作会如何导致问题的建议)。
根据我的测试,第一个示例获得了正确的行为,而第二个则没有。我认为在后一种情况下 import *
将获取 foo
的未修补版本,更新 alpha.foo
将包装 bar
调用但不会调用的 foo
的函数版本' t 影响本地名称空间中的 foo
。
正确:
import alpha
def _wrapper(func):
def call(*args, **kwargs):
print('entering')
result = func(*args, **kwargs)
print('exiting')
return result
return call
alpha.__dict__['foo'] = _wrapper(alpha.foo)
from alpha import *
输出(两个函数都调用补丁foo
):
entering
exiting
foo
entering
exiting
('foo', 'bar')
不正确:
import alpha
from alpha import *
def _wrapper(func):
def call(*args, **kwargs):
print('entering')
result = func(*args, **kwargs)
print('exiting')
return result
return call
alpha.__dict__['foo'] = _wrapper(alpha.foo)
输出(仅bar
调用补丁foo
,foo
不调用):
foo
entering
exiting
('foo', 'bar')
我不完全确定你的 objective,但你可以执行类似于以下操作的操作:
alpha.py
# everything here is the same
def foo():
return 'foo'
def bar():
return foo(), 'bar'
debug.py 使用 inspect module 找到定义函数的原始模块。
# make the debug module reusable
import inspect
def _wrapper(func):
def call(*args, **kwargs):
print('entering')
result = func(*args, **kwargs)
print('exiting')
return result
return call
def _wrapFunc(func):
# find out which module the original function was
# declared and wrap it.
module = inspect.getmodule(func)
wrapped = _wrapper(func)
setattr(module, func.__name__, wrapped)
# return the wrapped function so that the module
# that called this function can have access to the
# newly created function
return wrapped
test_alpha.py
# make test.py the testing script instead of depending on
# debug_alpha to handle hardcoded namespaces
import debug_alpha
from alpha import *
# wrap the function in its original module
# and override the wrapped function in this namespace
foo = debug_alpha._wrapFunc(foo)
print(foo())
print(bar())
输出
entering
exiting
foo
entering
exiting
('foo', 'bar')
我有一组测试包装了特定模块的一些功能,假设它看起来像这样:
alpha.py
def foo():
return 'foo'
def bar():
return foo(), 'bar'
debug_alpha.py
from alpha import *
def _wrapper(func):
def call(*args, **kwargs):
print('entering')
result = func(*args, **kwargs)
print('exiting')
return result
return call
def _wrapFunc(module, func):
module.__dict__[func.__name__] = _wrapper(func)
test.py
import debug_alpha
debug_alpha._wrapFunc(debug_alpha, debug_alpha.foo)
print(debug_alpha.foo())
print(debug_alpha.bar())
当然输出只有:
entering
exiting
foo
('foo', 'bar')
因为虽然 foo
函数可能已被包装 - bar
仍然引用原始 alpha
模块中的 foo
函数。是否有一种技巧可以将 foo
包装成 bar
也将在不更改导入模式的情况下调用适当的 foo
?
如果你想要 bar
调用包装的 foo
,你必须 替换 foo
在你的 alpha
模块中通过分配包装函数:alpha.foo = _wrapper(alpha.foo)
(或像在 _wrapFunc
中那样更新 alpha.__dict__
)。
在Python中,代码是数据,程序"symbols"与普通变量没有区别。每当 bar
中的代码即将调用 foo
时,Python 解释器将查找 foo
的定义,无论它位于 that[=30] =]时刻.
请注意,执行此类操作会在运行时更改您的程序,使其行为方式在源代码中并不明显。该技术称为 monkey patching(WP 文章有关于如果不小心操作会如何导致问题的建议)。
根据我的测试,第一个示例获得了正确的行为,而第二个则没有。我认为在后一种情况下 import *
将获取 foo
的未修补版本,更新 alpha.foo
将包装 bar
调用但不会调用的 foo
的函数版本' t 影响本地名称空间中的 foo
。
正确:
import alpha
def _wrapper(func):
def call(*args, **kwargs):
print('entering')
result = func(*args, **kwargs)
print('exiting')
return result
return call
alpha.__dict__['foo'] = _wrapper(alpha.foo)
from alpha import *
输出(两个函数都调用补丁foo
):
entering
exiting
foo
entering
exiting
('foo', 'bar')
不正确:
import alpha
from alpha import *
def _wrapper(func):
def call(*args, **kwargs):
print('entering')
result = func(*args, **kwargs)
print('exiting')
return result
return call
alpha.__dict__['foo'] = _wrapper(alpha.foo)
输出(仅bar
调用补丁foo
,foo
不调用):
foo
entering
exiting
('foo', 'bar')
我不完全确定你的 objective,但你可以执行类似于以下操作的操作:
alpha.py
# everything here is the same
def foo():
return 'foo'
def bar():
return foo(), 'bar'
debug.py 使用 inspect module 找到定义函数的原始模块。
# make the debug module reusable
import inspect
def _wrapper(func):
def call(*args, **kwargs):
print('entering')
result = func(*args, **kwargs)
print('exiting')
return result
return call
def _wrapFunc(func):
# find out which module the original function was
# declared and wrap it.
module = inspect.getmodule(func)
wrapped = _wrapper(func)
setattr(module, func.__name__, wrapped)
# return the wrapped function so that the module
# that called this function can have access to the
# newly created function
return wrapped
test_alpha.py
# make test.py the testing script instead of depending on
# debug_alpha to handle hardcoded namespaces
import debug_alpha
from alpha import *
# wrap the function in its original module
# and override the wrapped function in this namespace
foo = debug_alpha._wrapFunc(foo)
print(foo())
print(bar())
输出
entering
exiting
foo
entering
exiting
('foo', 'bar')