如何在Python中包装内置方法?(或';如何通过引用传递它们';)
我想用一个包装器包装默认的open方法,该包装器还应该捕获异常。下面是一个有效的测试示例:如何在Python中包装内置方法?(或';如何通过引用传递它们';),python,exception-handling,wrapper,Python,Exception Handling,Wrapper,我想用一个包装器包装默认的open方法,该包装器还应该捕获异常。下面是一个有效的测试示例: truemethod = open def fn(*args, **kwargs): try: return truemethod(*args, **kwargs) except (IOError, OSError): sys.exit('Can\'t open \'{0}\'. Error #{1[0]}: {1[1]}'.format(args[0],
truemethod = open
def fn(*args, **kwargs):
try:
return truemethod(*args, **kwargs)
except (IOError, OSError):
sys.exit('Can\'t open \'{0}\'. Error #{1[0]}: {1[1]}'.format(args[0], sys.exc_info()[1].args))
open = fn
我想做一个通用的方法:
def wrap(method, exceptions = (OSError, IOError)):
truemethod = method
def fn(*args, **kwargs):
try:
return truemethod(*args, **kwargs)
except exceptions:
sys.exit('Can\'t open \'{0}\'. Error #{1[0]}: {1[1]}'.format(args[0], sys.exc_info()[1].args))
method = fn
但它不起作用:
>>> wrap(open)
>>> open
<built-in function open>
>换行(打开)
>>>打开
显然,
method
是参数的副本,而不是我所期望的引用。任何pythonic解决方法?尝试添加全局打开。在一般情况下,您可能需要查看:
该模块提供对Python所有“内置”标识符的直接访问;例如,\uuuuuuuuuuuuuu内置函数的全名是open
。见第章
大多数应用程序通常不会显式访问此模块,但在提供与内置值同名的对象,但也需要该名称的内置对象的模块中,此模块非常有用。例如,在要实现封装内置函数的open()函数的模块中,可以直接使用此模块:
import __builtin__
def open(path):
f = __builtin__.open(path, 'r')
return UpperCaser(f)
class UpperCaser:
'''Wrapper around a file that converts output to upper-case.'''
def __init__(self, f):
self._f = f
def read(self, count=-1):
return self._f.read(count).upper()
# ...
CPython实现细节:大多数模块的名称\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
(注意“s”)作为其全局模块的一部分提供。\uuuuuuuuuuuuu内置项的值通常是此模块或此模块的\uuuuuuuu dict\uuuuuuuuu
属性的值。由于这是一个实现细节,Python的替代实现可能不会使用它
您只需在wrap
函数的末尾添加return fn
,然后执行以下操作:
>>> open = wrap(open)
>>> open('bhla')
Traceback (most recent call last):
File "<pyshell#24>", line 1, in <module>
open('bhla')
File "<pyshell#18>", line 7, in fn
sys.exit('Can\'t open \'{0}\'. Error #{1[0]}: {1[1]}'.format(args[0], sys.exc_info()[1].args))
SystemExit: Can't open 'bhla'. Error #2: No such file or directory
>>打开=换行(打开)
>>>开放(“bhla”)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
开放(“bhla”)
文件“”,第7行,fn中
sys.exit('无法打开\'{0}'。错误{1[0]}:{1[1]}'。格式(args[0],sys.exc_info()[1].args))
系统退出:无法打开“bhla”。错误2:没有这样的文件或目录
代码的问题在于,在wrap
内部,您的method=fn
语句只是更改method
的局部值,而不是更改open
的较大值。您必须自己为这些名称分配:
def wrap(method, exceptions = (OSError, IOError)):
def fn(*args, **kwargs):
try:
return method(*args, **kwargs)
except exceptions:
sys.exit('Can\'t open \'{0}\'. Error #{1[0]}: {1[1]}'.format(args[0], sys.exc_info()[1].args))
return fn
open = wrap(open)
foo = wrap(foo)
这对于一般情况来说似乎有点特殊。哎哟,那么您的意思是要将其替换为对open
函数的任何访问?听起来根本不像OP想要的,这不是包装,而是一个全球性的变化。@RedGlyph:是的,我就是这样解释最初的问题的。这不难,但很邪恶。将\u oldopen=\uuuu内置\uuuuu.open
然后将\uuuuu内置\uuuuuuuuu.open=open
放在此处引用的模块代码中,您已将其替换到所有位置。除了那些在导入此模块之前通过从uuuuuuuuuuuuuuuuuuuuuuuuuuuuu导入打开
导入的人。(啊,等等..在实现替换之前将旧的打开保存在\u oldopen
中,并通过\u oldopen
调用旧的,当然,以避免递归!:-)+1,这是一个好的解决方案。除了更一般的内容外,消息不应该提到“无法打开”(我知道已经在OP的帖子中了)。好的,所以基本上它可以作为我自己方法的装饰器。这是一个很好的答案,我在这里发表了一条评论,如果你真的想替换\uu内置\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。我只是想指出,在这里,您将Python的对象名称与变量混淆了open=..
仅(重新)绑定指定范围内的名称open
;您没有做的是重新绑定内置名称open
。也许您认为,open
是一个可以通过赋值来更改的对象,但是在Python中没有这样的对象。谢谢,现在它有意义了。