Python 像在自己的调用者中一样调用函数?
我正在尝试复制一种错误检查模式,这是我在用C和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)
检查,如下所示:
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
[]