我正在尝试复制我在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
必须执行,就好像它是在调用者范围内编写的一样wrapped
。 (handler
不一定是函数对象。我是在效果之后,而不是方法。)
在C中,我只是使用宏并扩展内联所有内容(因为这是我编写代码的地方),但Python没有宏。是否有可能以其他方式实现这种效果?
答案 0 :(得分:1)
无法编写Python代码来创建对象c
,因此,当您调用c
时,调用它的函数将返回。您只能通过直接在该函数体中直接键入return
语句(或从结尾处掉落)来从函数返回。
你可以很容易地做到这一点,以便你的"检查"函数只需返回默认值。然后呼叫者可以正常使用它,但它不能使呼叫者自己返回。您还可以为caller
编写一个装饰器来捕获指定的错误并返回[]
,但这会捕获OSError
中任何位置引发的所有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
可能会在许多不同的点上引发OSError
。如果您只有一个地方需要抓住[]
并返回OSError
,那么只需写一次尝试/除外,这没什么大不了的。如果你想在函数中捕获任何 []
并返回OSError
,请按照上面的说明进行装饰。您所描述的内容似乎仅在您想要捕获caller
中提出的多于一个但不是全部可能{{1}}的情况下才有用,但在所有这些情况下您想要返回相同的特定值,这似乎很不寻常。
答案 1 :(得分:0)
如果我不太明白,请原谅我,但是你不能把处理程序放在调用函数中吗?
def caller():
def handler():
print("Handler was called")
# ...
或者,如果您想简化调用方式,可以使用with
语句来达到预期效果。我认为这将变得更加容易,并且它不是一个“黑客”:
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')
输出是:
>>> with LogOSError('some_location'): ... os.unlink('/does/not/exist') ... some_location: OSError: [Errno 2] No such file or directory: '/does/not/exist'