0

我正在尝试复制在 Python 中使用 C 编程时经常使用的错误检查模式。我有一个功能check如下:

def check(exceptions, msg, handler):
    def wrapped(func, *args, **kwargs):
        try:
            return func(*args, **kwargs)
        except exceptions as err:
            log_err(msg)
            # Do something with handler
    return wrapped

通过check使用适当的参数调用,然后使用函数及其参数调用结果,可以在try-except不牺牲清晰度的情况下将语句减少到两行代码(无论如何,在我看来)。

例如

def caller():
    try:
        files = listdir(directory)
    except OSError as err:
        log_err(msg)
        return []
    # Do something with files

变成

def caller():
    c = check(OSError, msg, handler)
    files = c(listdir, directory) # caller may return [] here
    # Do something with files

问题是,为了使这种转换对程序的其余部分透明,必须handler像在. (不必是函数对象。我追求的是效果,而不是方法。)wrappedhandler

在 CI 中只会使用宏并内联扩展所有内容(因为无论如何我都会在那里编写代码),但 Python 没有宏。是否有可能以其他方式实现这种效果?

4

2 回答 2

1

没有办法编写 Python 代码来创建对象c,以便在您调用 时c,调用它的函数返回。您只能通过return直接在该函数的主体中直接键入语句(或从结尾处掉下来)来从函数返回。

您可以轻松地做到这一点,以便您的“已检查”函数仅返回默认值。然后调用者可以正常使用它,但不能让调用者本身返回。您也可以编写一个装饰器来caller捕获您指定的错误并返回[],但这会捕获所有OSError在 s 中的任何地方引发的 s caller,而不仅仅是通过调用特定函数(例如listdir)引发的那些。例如:

def check(exceptions, msg, handler):
    def deco(func):
        def wrapped(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except exceptions as err:
                print "Logged error:", msg
                return handler(err)
        return wrapped
    return deco

def handler(err):
    return []

@check(ZeroDivisionError, "divide by zero", handler)
def func(x):
    1/0

>>> func(1)
Logged error: divide by zero
[]

你描述的情况似乎有些不寻常。在大多数情况下,将处理分解为“处理程序”函数是值得的,该处理程序函数要么不知道它希望调用者返回什么值,要么它可以仅根据错误知道要返回什么,而无需知道是哪一行引发了错误。

例如,在您的示例中,您显然有一个caller可能会OSError在许多不同点引发 a 的函数。如果你只有一个地方需要 catchOSError和 return [],只需写一个 try/except ,这没什么大不了的。如果您想在函数中捕获任何 OSError内容并返回[],请如上所示对其进行装饰。您所描述的似乎仅在您想要捕获不止一个但不是所有可能OSError的情况下才有用caller异常。

于 2013-04-01T06:00:42.897 回答
0

如果我不太明白,请原谅我,但是您不能将处理程序放在调用函数中吗?

def caller():
    def handler():
        print("Handler was called")
    # ... 

更好的方法...

或者,如果你想简化你调用它的方式,你可以使用with语句来达到想要的效果。我认为这会容易得多,而且它的“hack”要少得多:

class LogOSError(object):
    def __init__(self, loc):
        self.loc = loc
    def __enter__(self):
        return None
    def __exit__(self, exc_type, exc_value, traceback):
        if isinstance(exc_value, OSError):
            print("{}: OSError: {}".format(self.loc, exc_value))
            return True

你可以像这样使用它:

with LogOSError('example_func'):
    os.unlink('/does/not/exist')

输出是:

>>> 使用 LogOSError('some_location'):
... os.unlink('/does/not/exist')
...
some_location: OSError: [Errno 2] 没有这样的文件或目录:'/does/not/exist'
于 2013-04-01T05:33:18.560 回答