Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 是否包装使用import*导入的函数?_Python_Introspection - Fatal编程技术网

Python 是否包装使用import*导入的函数?

Python 是否包装使用import*导入的函数?,python,introspection,Python,Introspection,我有一组测试,它们封装了特定模块的一些函数,假设它看起来是这样的: alpha.py def foo(): return 'foo' def bar(): return foo(), 'bar' from alpha import * def _wrapper(func): def call(*args, **kwargs): print('entering') result = func(*args, **kwargs)

我有一组测试,它们封装了特定模块的一些函数,假设它看起来是这样的:
alpha.py

def foo(): 
    return 'foo'
def bar(): 
    return foo(), 'bar'
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)
import debug_alpha
debug_alpha._wrapFunc(debug_alpha, debug_alpha.foo)
print(debug_alpha.foo())
print(debug_alpha.bar())
debug_alpha.py

def foo(): 
    return 'foo'
def bar(): 
    return foo(), 'bar'
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)
import debug_alpha
debug_alpha._wrapFunc(debug_alpha, debug_alpha.foo)
print(debug_alpha.foo())
print(debug_alpha.bar())
test.py

def foo(): 
    return 'foo'
def bar(): 
    return foo(), 'bar'
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)
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

如果希望
调用包装的
foo
,则必须在
alpha
模块中替换
foo
,方法是指定包装函数:
alpha.foo=\u wrapper(alpha.foo)
(或像在
\u wrapFunc
中一样更新
alpha.\u dict\uu

在Python中,代码是数据,程序“符号”与普通变量没有区别。每当
bar
中的代码即将调用
foo
时,Python解释器将查找
foo
的定义,无论此时是什么


请注意,这样做会在运行时更改程序,使其以源代码中不明显的方式运行。这种技术被称为(WP文章中有关于如果不小心这样做会导致问题的建议)。

通过我的测试,第一个示例获得了正确的行为,而第二个示例没有。我认为在后一种情况下,
import*
将获取未修补版本的
foo
,更新
alpha.foo
将包装
foo
的函数版本,该函数版本调用
bar
,但不会影响本地命名空间中的
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
):

不正确:

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
不调用):


我不完全确定你的目标,但你可以做如下类似的事情:

alpha.py

# everything here is the same
def foo(): 
    return 'foo'

def bar(): 
    return foo(), 'bar'
# 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())
debug.py使用查找函数定义的原始模块

# 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
测试α.py

# everything here is the same
def foo(): 
    return 'foo'

def bar(): 
    return foo(), 'bar'
# 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')

您希望输出是什么?@jedwards我希望包装器在
bar()
上被触发,但我想我得到了它,可以
导入alpha
并包装
alpha.\uu dict\uuuuo['foo']
,然后从alpha导入调用
。如果我不再需要答案,我应该结束这个问题吗?如果你认为它对未来的观众有帮助(我不明白为什么它不会,与这里的许多问题相比),请回答你自己的问题。我想你会因此得到一枚漂亮的徽章。你也可以在
wrapFunc
中添加一行,比如
alpha.\uuu dict\uuuu[func.\uuu name\uuuu]=\u wrapper(func)
(在
导入alpha
之后)。我将此标记为正确,因为我认为它适合一般情况,有一点可能需要强调的是,你正在用\u wrapFunc包装两个独立的对象,一个用于函数调用,一个用于返回。