我在Python中有一段代码似乎在概率上导致错误,因为它正在访问服务器,有时该服务器有500内部服务器错误。我想继续尝试,直到我没有得到错误。我的解决方案是:
while True:
try:
#code with possible error
except:
continue
else:
#the rest of the code
break
这对我来说似乎是个黑客。有更多的Pythonic方法吗?
答案 0 :(得分:48)
它不会变得更清洁。这不是一件非常干净的事情。充其量(无论如何都会更具可读性,因为break
的条件与while
一致),您可以创建变量result = None
并循环{{1} }。您还应该调整变量,并且可以用语义上正确的is None
替换continue
(您不关心是否发生错误,您只是想忽略它)并删除pass
- 这也得到了剩下的代码,它只执行一次,不在循环中。另请注意,由于[{3}} {。}}原因,break
个条款是不正当的。
包含以上所有内容的示例:
except:
答案 1 :(得分:20)
也许是这样的:
connected = False
while not connected:
try:
try_connect()
connected = True
except ...:
pass
答案 2 :(得分:18)
这是一次尝试4次后硬盘失败,并在两次尝试之间等待2秒。根据您的意愿改变你想要的东西:
from time import sleep
for x in range(0, 4): # try 4 times
try:
# msg.send()
# put your logic here
str_error = None
except Exception as str_error:
pass
if str_error:
sleep(2) # wait for 2 seconds before trying to fetch the data again
else:
break
以下是退避的示例:
from time import sleep
sleep_time = 2
num_retries = 4
for x in range(0, num_retries):
try:
# put your logic here
str_error = None
except Exception as str_error:
pass
if str_error:
sleep(sleep_time) # wait before trying to fetch the data again
sleep_time *= 2 # Implement your backoff algorithm here i.e. exponential backoff
else:
break
答案 3 :(得分:3)
itertools.iter_except
配方封装了这个"重复调用函数的想法,直到引发异常为止#34;。它类似于接受的答案,但是配方给出了迭代器。
从食谱中:
def iter_except(func, exception, first=None):
""" Call a function repeatedly until an exception is raised."""
try:
if first is not None:
yield first() # For database APIs needing an initial cast to db.first()
while True:
yield func()
except exception:
pass
您当然可以直接实现后一种代码。为方便起见,我使用了一个单独的库more_itertools
,它为我们实现了这个配方(可选)。
<强>代码强>
import more_itertools as mit
list(mit.iter_except([0, 1, 2].pop, IndexError))
# [2, 1, 0]
<强>详情
这里为列表对象的每次迭代调用pop
方法(或给定函数),直到引发IndexError
。
对于你的情况,给定一些connect_function
和预期的错误,你可以创建一个重复调用函数的迭代器,直到引发异常,例如
mit.iter_except(connect_function, ConnectionError)
此时,通过循环或调用next()
将其视为任何其他迭代器。
答案 4 :(得分:2)
这是我编写的一个实用程序函数,用于包装重试,直到成功进入neater包。它使用相同的基本结构,但可以防止重复。可以修改它以便在最后的尝试中相对容易地捕获和重新抛出异常。
def try_until(func, max_tries, sleep_time):
for _ in range(0,max_tries):
try:
return func()
except:
sleep(sleep_time)
raise WellNamedException()
#could be 'return sensibleDefaultValue'
然后可以这样调用
result = try_until(my_function, 100, 1000)
如果你需要将参数传递给my_function
,你可以通过让try_until
转发参数,或者将它包装在无参数lambda中来实现:
result = try_until(lambda : my_function(x,y,z), 100, 1000)
答案 5 :(得分:1)
也许装饰师基于? 您可以传递我们想要重试的异常和/或尝试次数的装饰器参数列表。
def retry(exceptions=None, tries=None):
if exceptions:
exceptions = tuple(exceptions)
def wrapper(fun):
def retry_calls(*args, **kwargs):
if tries:
for _ in xrange(tries):
try:
fun(*args, **kwargs)
except exceptions:
pass
else:
break
else:
while True:
try:
fun(*args, **kwargs)
except exceptions:
pass
else:
break
return retry_calls
return wrapper
from random import randint
@retry([NameError, ValueError])
def foo():
if randint(0, 1):
raise NameError('FAIL!')
print 'Success'
@retry([ValueError], 2)
def bar():
if randint(0, 1):
raise ValueError('FAIL!')
print 'Success'
@retry([ValueError], 2)
def baz():
while True:
raise ValueError('FAIL!')
foo()
bar()
baz()
当然'try'部分应该转移到另一个函数因为我们在两个循环中使用它但它只是示例;)
答案 6 :(得分:1)
与大多数其他人一样,我建议尝试有限次数并在尝试之间休息。这样,如果远程服务器实际发生某些事情,您就不会发现自己处于无限循环中。
我还建议您只在获得预期的特定异常时继续。这样,您仍然可以处理您可能不期望的异常。
from urllib.error import HTTPError
import traceback
from time import sleep
attempts = 10
while attempts > 0:
try:
#code with possible error
except HTTPError:
attempts -= 1
sleep(1)
continue
except:
print(traceback.format_exc())
#the rest of the code
break
此外,您不需要其他块。由于except块中的continue,你跳过循环的其余部分,直到try块工作,while条件得到满足,或HTTPError以外的异常出现。
答案 7 :(得分:1)
e = ''
while e == '':
try:
response = ur.urlopen('https://https://raw.githubusercontent.com/MrMe42/Joe-Bot-Home-Assistant/mac/Joe.py')
e = ' '
except:
print('Connection refused. Retrying...')
time.sleep(1)
这应该有效。它将e设置为'',而while循环检查它是否仍然''。如果捕获的错误是try语句,则打印出连接被拒绝,等待1秒然后重新开始。它将继续运行直到try中没有错误,然后将e设置为'',这会导致while循环。
答案 8 :(得分:0)
这是我用来将错误捕获为字符串的一小段代码。将重试直到成功。这会捕获所有异常,但您可以根据需要进行更改。
start = 0
str_error = "Not executed yet."
while str_error:
try:
# replace line below with your logic , i.e. time out, max attempts
start = raw_input("enter a number, 0 for fail, last was {0}: ".format(start))
new_val = 5/int(start)
str_error=None
except Exception as str_error:
pass
警告:此代码将停留在永久循环中,直到不会发生异常。这只是一个简单的例子,MIGHT要求您尽快摆脱循环或在重试之间休眠。
答案 9 :(得分:0)
由于错误重试时,您应该始终:
解决这些问题的一种简单通用方法是使用backoff库。一个基本的例子:
import backoff
@backoff.on_exception(
backoff.expo,
MyException,
max_tries=5
)
def make_request(self, data):
# do the request
此代码用装饰器包装make_request,该装饰器实现重试逻辑。每当发生我们的特定错误MyException
时,我们都会重试,最多可以重试5次。在这种情况下,Exponential backoff是一个好主意,可以最大程度地减少我们重试在远程服务器上带来的额外负担。
答案 10 :(得分:0)
retrying library on pypi呢? 我已经使用了一段时间了,它确实可以满足我的要求(更多)(重试错误,重试“无”,超时重试)。下面是他们网站上的示例:
putchar(c);
答案 11 :(得分:0)
我现在正在尝试这样做,这就是我想出的;
theory T : ?Meta =
structure s1 : ?S = ❚
structure s2 : ?S = ❚
n: ℕ ❙
c_usage1 = n s1/+ n ❙
c_usage2 = n s2/+ n ❙
c_usage_combined = (n s1/+ n) ∨ (n s2/+ n) ❙
d_usage1 = n s1/|- n ∶ n ❙
d_usage2 = n s2/|- n ∶ n ❙
d_usage_combined = (n s1/|- n ∶ n) ∨ (n s2/|- n ∶ n) ❙
❚
答案 12 :(得分:0)
这里有许多不同的答案,但我感到没有一个可以成功满足我的需求(或更重要的是,提问者的需求),因此我结合了一些出色的答案,并放入了自己的不太秘密的调味料提出以下配方:
successful = False
attempts = [0]
authorized_attempts = 10
while sum(attempts) < authorized_attempts and not successful:
try:
attempts.append(1)
if EXPECTED_RESULT in result():
print(f"Success on attempt number {sum(attempts)}.")
attempts = [0]
successful = True
except Exception:
print(f"Failure on attempt number {sum(attempts)}.")
time.sleep(5)