修改函数中的每个for循环,以便在每次迭代失败后自动执行错误处理 [英] Alter each for-loop in a function to have error handling executed automatically after each failed iteration

查看:113
本文介绍了修改函数中的每个for循环,以便在每次迭代失败后自动执行错误处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题出自发生器内的错误,然后继续

我有大约50个类似(但不同)的功能,试图从网站中提取URL等。因为每个网站是不同的,每个功能是不同的,因为网站往往会随着时间的推移变化这个代码是混乱的,不能被信任。



这是一个简化的示例,或看看在第一个问题中的示例

  def _get_units(self):
用于self.get_list1()中的list1 self.get_list2(list1)中的list2的b $ b:list2中单元的

产生单元

我想用这个函数做的事情本质上改变了行为来匹配这个:

  def _get_units (self):
用于self.get_list1()中的list1:
try:
用于self.get_list2(list1)中的list2:
try:
for unit in list2:
try:
产生单位
除了例外e:
log_exception(e)
除了作为e:
的例外,log_exception(e)
除了作为e的例外:
log_exception(e)

简而言之,我想为列表中的x

  do_stuff(x)

对此:

<$
试试:
do_stuff(x)
除了Exception:e
log_exception(e)

对于我的函数中的每个 for



但我想用pythonic的方式做。我不想要 try:除了块之外,我需要改变50个函数。这可能吗?如果是这样,我怎样才能以最干的方式做到这一点,我可以做到这一点在一个地方的错误处理?



更新:这个问题以前包括一个继续声明与日志记录,但如mgilson指出,这是没有必要的。

更新2 与georgesl的答案功能变成如下:

  from contextlib import contextmanager 

@contextmanager
Error ErrorManaged():
尝试:
产生
除了例外e:
log_exception(e)
self.get_list1():
with ErrorManaged():
def_get_units(self):
在self.get_list2(list1)中为list2:

与ErrorManaged():
在list2中的单位:
与ErrorManaged():
产量单位

其中i确实很干净。不过,单纯的装饰者会更好。谁能告诉我这是可能的吗?如果没有,我会接受georgesl的答案。

解决方案

我给了这个更多的想法,唯一的解决方案,似乎是修改代码本身。所以这里是:

  from contextlib import contextmanager 
import inspect
$ b $ @contextmanager
def ErrorManaged():
尝试:
产生
,除了例外e:
print e



def get_units():
在范围内(-5,5):
print(x)
$ b $如果x%3 == 0:
异常(x):
print(\t {}。format(y))

如果y%3 == 0:
在范围(-5,5)中给出例外(y nope)


print(\t \t {}。format(z))

如果z%3 == 0:
抛出异常(z nope)


import re
$ b $ def modify_get_units(get_units):
lines = inspect.getsourcelines(get_units)[0]
add =ErrorManaged():\\\

new = []
tabize = 0
for c in行[1]:
if c ==:
tabize + = 1
else:
break

count = 0
对于行:
new.append(* tabsize * count + line)
m = re.match(r^(\ s +)for \s [()\w, ] + \sin\s [^:\\\
] +:\\\
$,line)
if m:
count + = 1
new.append(m。 group(1)+* tabsize * count + add)

return.join(new)
$ b oldfunc = inspect.getsource(get_units)
newfunc = modify_get_units(get_units)

#打印函数体显示结果

print(oldfunc)
print(\\\
\\\
\\\

print(newfunc)


#re-declare get_units
exec newfunc

#execute,但现在是
#get_units()

输出:

  toon @ ToonAlfrinkPC〜$ python test.py 
def get_units():
for x(-5,5):
打印(x)

如果x%3 == 0:
例外(x nope)

在范围内(-5,5) :
print(\t {}。format(y))

if y%3 == 0:
抛出Exception(y nope)$ b (-5,5):
print(\t\t {}。格式(z))

如果z% 3 == 0:
抛出异常(z nope)





def get_units():
(-5,5)中的x:
与ErrorManaged():
print(x)

if x%3 == 0:
raise Exception (x nope)

(-5,5):
with ErrorManaged():
print(\t {}。format y))

如果y%3 == 0:
在范围(-5,5)中为z提升异常(y nope)


与ErrorManaged():
print(\t\t {}。format(z))

if z%3 == 0:
Exception Exception z nope)

感谢您帮助我到达!


This question follows from catch errors within generator and continue afterwards

I have about 50 similar (but different) functions which try to extract URLs and such from websites. Because each website is different, each function is different and because websites tend to change over time this code is messy and cannot be trusted.

Here's a simplified sample, or look at the sample in the first question

def _get_units(self):
    for list1 in self.get_list1():
        for list2 in self.get_list2(list1):
            for unit in list2:
                yield unit

What I want to do with this function is essentially change the behavior to match this:

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)

In short, I want to turn this

for x in list:
    do_stuff(x)

to this:

for x in list:
    try:
        do_stuff(x)
    except Exception as e:
        log_exception(e)

for each for in my functions.

But I want to do it in a pythonic way. I don't want try:except blocks scattered all over the 50 functions I need to alter. Is this possible? If so, how can I do it in the most DRY way, and can I do this with the error handling in one place?

UPDATE: this question formerly included a continue statement along with the logging, but as mgilson pointed out, this isn't necessary.

UPDATE 2 with georgesl's answer the function becomes as follows:

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

which is a lot cleaner indeed. though, a mere decorator would be even better. can anyone tell me if this is possible? if not, i'll accept georgesl's answer.

解决方案

I gave this some more thought, the only solution to really suit my needs seems to be to modify the code itself. So here goes:

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()

output:

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")

Thanks for helping me get there!

这篇关于修改函数中的每个for循环,以便在每次迭代失败后自动执行错误处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆