Python 更改函数中的每个for循环,以便在每次失败的迭代后自动执行错误处理
这个问题源自 我有大约50个类似(但不同)的函数,试图从网站中提取URL等。因为每个网站都不同,每个功能也不同,而且网站往往会随着时间的推移而改变,所以这些代码很混乱,不可信 这是一个简化的示例,或者看看第一个问题中的示例Python 更改函数中的每个for循环,以便在每次失败的迭代后自动执行错误处理,python,for-loop,Python,For Loop,这个问题源自 我有大约50个类似(但不同)的函数,试图从网站中提取URL等。因为每个网站都不同,每个功能也不同,而且网站往往会随着时间的推移而改变,所以这些代码很混乱,不可信 这是一个简化的示例,或者看看第一个问题中的示例 def _get_units(self): for list1 in self.get_list1(): for list2 in self.get_list2(list1): for unit in list2:
def _get_units(self):
for list1 in self.get_list1():
for list2 in self.get_list2(list1):
for unit in list2:
yield unit
我想对这个函数做的是,本质上改变行为以匹配以下内容:
def _get_units(self):
for list1 in self.get_list1():
try:
for list2 in self.get_list2(list1):
try:
for unit in list2:
try:
yield unit
except Exception as e:
log_exception(e)
except Exception as e:
log_exception(e)
except Exception as e:
log_exception(e)
简言之,我想扭转这一局面
for x in list:
do_stuff(x)
为此:
for x in list:
try:
do_stuff(x)
except Exception as e:
log_exception(e)
对于我的函数中的每个
但我想用一种蟒蛇式的方式。我不想尝试:除了散落在我需要修改的50个函数上的
块。这可能吗?如果是这样的话,我怎样才能以最干涸的方式来做呢?我可以在一个地方用错误处理来做这件事吗
更新:这个问题以前在日志记录中包含了一个continue
语句,但正如mgilson所指出的,这是不必要的
使用georgesl的答案更新2函数如下所示:
from contextlib import contextmanager
@contextmanager
def ErrorManaged():
try:
yield
except Exception as e:
log_exception(e)
def _get_units(self):
for list1 in self.get_list1():
with ErrorManaged():
for list2 in self.get_list2(list1):
with ErrorManaged():
for unit in list2:
with ErrorManaged():
yield unit
这确实干净多了。不过,仅仅是一个装饰师就更好了。有人能告诉我这是否可行吗?如果没有,我将接受乔治的回答。我可能会“装饰”函数本身。如果你生活在枯燥的原则中,你可能会把它们存储在一个列表或其他东西中:
def decorate_function(func):
def decorated(x):
try:
return func(x)
except Exception as e:
log_error(e)
return decorated
现在你可以用它来修饰你的函数,它会记录你的错误。注意,这假设上面的continue
语句是不必要的。看起来我还不习惯,但我可能错过了什么
如果函数确实没有返回某些内容,那么您可以返回True
或False
,具体取决于您是否遇到异常。您可以使用它来编写continue
逻辑。比如:
if not decorated_function(x): continue
您可能需要使用装饰器或更好的:
我对此进行了更多的思考,真正符合我需求的唯一解决方案似乎是修改代码本身。下面是:
from contextlib import contextmanager
import inspect
@contextmanager
def ErrorManaged():
try:
yield
except Exception as e:
print e
def get_units():
for x in range(-5,5):
print(x)
if x % 3 == 0:
raise Exception("x nope")
for y in range(-5,5):
print("\t{}".format(y))
if y % 3 == 0:
raise Exception("y nope")
for z in range(-5,5):
print("\t\t{}".format(z))
if z % 3 == 0:
raise Exception("z nope")
import re
def modify_get_units(get_units):
lines = inspect.getsourcelines(get_units)[0]
add = "with ErrorManaged():\n"
new = []
tabsize = 0
for c in lines[1]:
if c == " ":
tabsize += 1
else:
break
count = 0
for line in lines:
new.append(" " * tabsize * count + line)
m = re.match(r"^(\s+)for\s[()\w,]+\sin\s[^ :\n]+:\n$",line)
if m:
count += 1
new.append(m.group(1) + " " * tabsize * count + add)
return "".join(new)
oldfunc = inspect.getsource(get_units)
newfunc = modify_get_units(get_units)
#printing function bodies to show results
print(oldfunc)
print("\n\n\n")
print(newfunc)
#re-declare get_units
exec newfunc
#execute, but now now
#get_units()
输出:
toon@ToonAlfrinkPC ~ $ python test.py
def get_units():
for x in range(-5,5):
print(x)
if x % 3 == 0:
raise Exception("x nope")
for y in range(-5,5):
print("\t{}".format(y))
if y % 3 == 0:
raise Exception("y nope")
for z in range(-5,5):
print("\t\t{}".format(z))
if z % 3 == 0:
raise Exception("z nope")
def get_units():
for x in range(-5,5):
with ErrorManaged():
print(x)
if x % 3 == 0:
raise Exception("x nope")
for y in range(-5,5):
with ErrorManaged():
print("\t{}".format(y))
if y % 3 == 0:
raise Exception("y nope")
for z in range(-5,5):
with ErrorManaged():
print("\t\t{}".format(z))
if z % 3 == 0:
raise Exception("z nope")
谢谢你帮我到达那里 您最内部的尝试是多余的--
yield
不会引发异常。在异常处理中continue
的目的是什么?也许我遗漏了什么,但似乎没必要。(请注意,如果您可以删除continue
,此问题会变得更严重。)easier@StevenRumbalski:由于第二个函数不是编写的,而是计算的,所以我让try:except
,因为不管循环的内容如何,它都会在那里。@mgilson想到它……我怎么没有注意到?如果我try:except
整个block,我不需要继续
…编辑…是否可以将一些错误处理移到get_list1
和get_list2
?@StevenRumbalski--但这不是上面的代码snipet所能做的,是吗?每个for
都包含一个try except
。因此,如果你发现一个错误,你会点击except>
然后是continue
,它只是继续当前循环。这是我想要的,但不是现在的情况。请注意,第二个代码段是我想要第一个代码段的行为方式,它不是现有的代码。@ToonAlfrink--我理解。我看不到的是您的两个示例之间的关系。(这两个版本是带有self…
的版本,在该版本中,与实际调用函数的版本相比,产生一个值。)不是说我不认识谷歌,但是你能提供一个到contextmanager
文档的链接吗?我也在考虑上下文管理器,但你还是每次都用…
重复部分,而不是修饰使其自动运行的函数。你是对的@mgilson,也许我可以用g来节省一些空间Generator,但我没有成功地使其工作。这看起来不错,但很抱歉,我还不熟悉with
语句。我已经尝试实现了这一点,但我没有真正理解它。请在我的函数中实现您的答案,以便我可以查看?和测试?
toon@ToonAlfrinkPC ~ $ python test.py
def get_units():
for x in range(-5,5):
print(x)
if x % 3 == 0:
raise Exception("x nope")
for y in range(-5,5):
print("\t{}".format(y))
if y % 3 == 0:
raise Exception("y nope")
for z in range(-5,5):
print("\t\t{}".format(z))
if z % 3 == 0:
raise Exception("z nope")
def get_units():
for x in range(-5,5):
with ErrorManaged():
print(x)
if x % 3 == 0:
raise Exception("x nope")
for y in range(-5,5):
with ErrorManaged():
print("\t{}".format(y))
if y % 3 == 0:
raise Exception("y nope")
for z in range(-5,5):
with ErrorManaged():
print("\t\t{}".format(z))
if z % 3 == 0:
raise Exception("z nope")