开发者

How to wrap built-in methods in Python? (or 'how to pass them by reference')

I want to wrap the default open method with a wrapper that should also catch exceptions. Here's a test example that works:

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

I want to make a generic method of it:

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_in开发者_如何学JAVAfo()[1].args))

    method = fn

But it doesn't work:

>>> wrap(open)
>>> open
<built-in function open>

Apparently, method is a copy of the parameter, not a reference as I expected. Any pythonic workaround?


The problem with your code is that inside wrap, your method = fn statement is simply changing the local value of method, it isn't changing the larger value of open. You'll have to assign to those names yourself:

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)


Try adding global open. In the general case, you might want to look at this section of the manual:

This module provides direct access to all ‘built-in’ identifiers of Python; for example, __builtin__.open is the full name for the built-in function open(). See chapter Built-in Objects.

This module is not normally accessed explicitly by most applications, but can be useful in modules that provide objects with the same name as a built-in value, but in which the built-in of that name is also needed. For example, in a module that wants to implement an open() function that wraps the built-in open(), this module can be used directly:

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 implementation detail: Most modules have the name __builtins__ (note the 's') made available as part of their globals. The value of __builtins__ is normally either this module or the value of this modules’s __dict__ attribute. Since this is an implementation detail, it may not be used by alternate implementations of Python.


you can just add return fn at the end of your wrap function and then do:

>>> 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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜