有没有一种Python式的方法可以尝试最多次数的东西?

2024-04-28 08:42:12 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个python脚本,它在共享linux主机上查询MySQL服务器。出于某种原因,对MySQL的查询经常返回一个“server has gone away”错误:

_mysql_exceptions.OperationalError: (2006, 'MySQL server has gone away')

如果紧接着再次尝试查询,通常会成功。所以,我想知道python中是否有一种明智的方法来尝试执行一个查询,如果失败,可以再试一次,最多可以尝试固定的次数。也许我想在完全放弃之前尝试5次。

下面是我的代码:

conn = MySQLdb.connect(host, user, password, database)
cursor = conn.cursor()

try:
    cursor.execute(query)
    rows = cursor.fetchall()
    for row in rows:
        # do something with the data
except MySQLdb.Error, e:
    print "MySQL Error %d: %s" % (e.args[0], e.args[1])

很明显,我可以通过在except子句中进行另一次尝试来做到这一点,但那是难以置信的丑陋,而且我觉得必须有一个体面的方法来实现这一点。


Tags: 方法脚本serverlinuxmysqlargserrorconn
3条回答

基于Dana的回答,您可能希望作为一名装饰师:

def retry(howmany):
    def tryIt(func):
        def f():
            attempts = 0
            while attempts < howmany:
                try:
                    return func()
                except:
                    attempts += 1
        return f
    return tryIt

然后。。。

@retry(5)
def the_db_func():
    # [...]

使用decorator模块

的增强版本
import decorator, time

def retry(howmany, *exception_types, **kwargs):
    timeout = kwargs.get('timeout', 0.0) # seconds
    @decorator.decorator
    def tryIt(func, *fargs, **fkwargs):
        for _ in xrange(howmany):
            try: return func(*fargs, **fkwargs)
            except exception_types or Exception:
                if timeout is not None: time.sleep(timeout)
    return tryIt

然后。。。

@retry(5, MySQLdb.Error, timeout=0.5)
def the_db_func():
    # [...]

要安装the ^{} module

$ easy_install decorator

更新:有一个更好维护的重试库分支,名为tenacity,它支持更多功能,总体上更灵活。


是的,这里有一个retrying library,它有一个decorator,它实现了多种重试逻辑,您可以组合这些逻辑:

一些例子:

@retry(stop_max_attempt_number=7)
def stop_after_7_attempts():
    print "Stopping after 7 attempts"

@retry(wait_fixed=2000)
def wait_2_s():
    print "Wait 2 second between retries"

@retry(wait_exponential_multiplier=1000, wait_exponential_max=10000)
def wait_exponential_1000():
    print "Wait 2^x * 1000 milliseconds between each retry,"
    print "up to 10 seconds, then 10 seconds afterwards"

怎么样:

conn = MySQLdb.connect(host, user, password, database)
cursor = conn.cursor()
attempts = 0

while attempts < 3:
    try:
        cursor.execute(query)
        rows = cursor.fetchall()
        for row in rows:
            # do something with the data
        break
    except MySQLdb.Error, e:
        attempts += 1
        print "MySQL Error %d: %s" % (e.args[0], e.args[1])

相关问题 更多 >