Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/324.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中包装内置方法?(或';如何通过引用传递它们';)_Python_Exception Handling_Wrapper - Fatal编程技术网

如何在Python中包装内置方法?(或';如何通过引用传递它们';)

如何在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],

我想用一个包装器包装默认的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], 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中没有这样的对象。谢谢,现在它有意义了。