Python 像在自己的调用者中一样调用函数?

Python 像在自己的调用者中一样调用函数?,python,debugging,Python,Debugging,我正在尝试复制一种错误检查模式,这是我在用C和Python编程时经常使用的模式。我有一个功能检查,如下所示: def check(exceptions, msg, handler): def wrapped(func, *args, **kwargs): try: return func(*args, **kwargs) except exceptions as err: log_err(msg)

我正在尝试复制一种错误检查模式,这是我在用C和Python编程时经常使用的模式。我有一个功能
检查
,如下所示:

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
必须完全按照在
wrapped
的调用者范围内编写的方式执行。(
handler
不必是函数对象。我追求的是效果,而不是方法。)


在C语言中,我只会使用宏并将所有内容内联扩展(因为我无论如何都要在内联中编写代码),但Python没有宏。是否可以通过其他方式实现此效果?

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

def caller():
    def handler():
        print("Handler was called")
    # ... 
更好的方法。。。 或者,如果您想简化调用它的方式,您可以使用
语句来实现所需的效果。我认为,这会容易得多,而且“黑客”也会少很多:

您可以这样使用它:

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

>>> with LogOSError('some_location'): ... os.unlink('/does/not/exist') ... some_location: OSError: [Errno 2] No such file or directory: '/does/not/exist' >>>使用LogOSError(“某个位置”): ... 取消链接(“/does/not/exist”) ... 某些位置:OSError:[Errno 2]没有这样的文件或目录:'/does/not/exist'
无法编写Python代码来创建对象
c
,这样,当您调用
c
时,调用它的函数将返回。您只能通过直接在函数体中键入
return
语句(或从末尾掉下来)从函数返回

您可以很容易地将其设置为“checked”函数只返回默认值。然后调用方可以正常使用它,但它不能使调用方本身返回。您还可以为
调用者
编写一个修饰符,该修饰符捕获指定的错误并返回
[]
,但这将捕获在
调用者
中任何位置引发的所有
操作错误
,而不仅仅是通过调用特定函数(例如,
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
[]
你所描述的情况似乎有些不同寻常。在大多数情况下,将处理分解为“handler”函数是值得的,该handler函数要么不知道它希望调用方返回什么值,要么只知道根据错误返回什么,而不需要知道是哪一行引起了错误


例如,在您的示例中,您显然有一个函数
调用者
,它可能在许多不同的点上引发
操作错误
。如果您只有一个地方需要捕获
OSError
并返回
[]
,只需编写一个try/except,这没什么大不了的。如果要捕获函数中的任何
OSError
,并返回
[]
,请按上图所示对其进行装饰。您所描述的内容似乎只在以下情况下有用:
调用者
中提出的一个以上但并非所有可能的
操作错误
,但在所有这些情况下,您都希望返回相同的特定值,这似乎很不寻常。

您能举一个示例说明如何使用它吗(即,您需要它做什么)?当然。我将添加一些更具体的内容。在您的示例中,您希望
handler
做什么?您是说如果出现错误,您希望调用
c(…)
的函数返回
[]
,还是希望表达式
c(…)
计算为
[]
?前者。
c(…)
的调用方应返回
[]
。显然,这只应该在
处理程序的效果可以说是“近在咫尺”时使用。我正在尝试复制一种在Python中用C编程时经常使用的错误检查模式。坏主意!将Python当作C编写会导致无法维护/非惯用代码。我希望
处理程序
能够影响调用方的r。不仅用于记录或返回值,而且用于实现一般效果。仅记录相对简单。使用
with
语句进行记录是一个有趣的想法,尽管我不确定如何避免有效地隐藏异常。@yew:您不必隐藏异常,这就是
返回True的原因
确实如此。啊,确实如此。我必须考虑一下
with
语句和
log\u err
函数中的哪一个读起来更好。这并不完全正确,但我会接受“不可能”来代替另一个答案。我确实希望对某些但不是所有特定类型的异常做出响应。我发现这个问题最常发生在
OSError
IOError
,可能是因为它们太通用了。
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
[]