Как обернуть встроенные методы в Python? (или «как передать их по ссылке») - PullRequest
3 голосов
/ 11 ноября 2009

Я хочу обернуть метод открытия по умолчанию оболочкой, которая также должна перехватывать исключения. Вот тестовый пример, который работает :

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 является копией параметра, а не ссылкой, как я ожидал. Есть ли питоническое решение?

Ответы [ 3 ]

3 голосов
/ 11 ноября 2009

Проблема с вашим кодом в том, что внутри 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)
2 голосов
/ 11 ноября 2009

Попробуйте добавить global open. В общем случае вы можете посмотреть этот раздел руководства :

Этот модуль обеспечивает прямой доступ ко всем «встроенным» идентификаторам Python; например, __builtin__.open - полное имя встроенной функции open () . См. Главу Встроенные объекты .

Этот модуль обычно не доступен явно в большинстве приложений, но может быть полезен в модулях, которые предоставляют объекты с тем же именем, что и встроенное значение, но в которых также требуется встроенное имя. Например, в модуле, который хочет реализовать функцию 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: большинство модулей имеют имя __builtins__ (обратите внимание на 's'), доступное как часть их глобальных переменных. Значение __builtins__ обычно является либо этим модулем, либо значением атрибута __dict__ этих модулей. Поскольку это деталь реализации, она не может использоваться альтернативными реализациями Python.

1 голос
/ 11 ноября 2009

Вы можете просто добавить return fn в конце вашей функции wrap и затем сделать:

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