尝试/除了班级中的每个方法?

Eli*_*Eli 2 python

我目前正在使用Google的BigQuery API,它在调用时偶尔会给我:

apiclient.errors.HttpError: <HttpError 500 when requesting https://www.googleapis.com/bigquery/v2/projects/some_job?alt=json returned "Unexpected. Please try again.">
Run Code Online (Sandbox Code Playgroud)

返回是一件很愚蠢的事情,但无论如何,当我为任何一种方法得到这个时,我只想睡一两秒然后再试一次.基本上,我想用以下方法包装每个方法:

def new_method
    try:
        method()
    except apiclient.errors.HttpError, e:
        if e.resp.status == 500:
            sleep(2)
            new_method()
        else:
            raise e
Run Code Online (Sandbox Code Playgroud)

这样做的好方法是什么?

我不想显式重新定义类中的每个方法.我只是想自动将一些东西应用到课堂上的每一个方法中,所以我对未来有所了解.理想情况下,我会采取一个类的对象,O,并围绕它的包装,重新定义每个方法的类此尝试不同的包装,所以我得到了一些新的对象,P,当它得到一个500错误自动重试.

shx*_*hx2 8

装饰师是完美的.您可以使用像这样的装饰器来装饰每个相关方法:

(注意使用递归进行重试可能不是一个好主意...)

def Http500Resistant(func):
    num_retries = 5
    @functools.wraps(func)
    def wrapper(*a, **kw):
        sleep_interval = 2
        for i in range(num_retries):
            try:
                return func(*a, **kw)
            except apiclient.errors.HttpError, e:
                if e.resp.status == 500 and i < num_retries-1:
                    sleep(sleep_interval)
                    sleep_interval = min(2*sleep_interval, 60)
                else:
                    raise e    
    return wrapper

class A(object):

    @Http500Resistant
    def f1(self): ...

    @Http500Resistant
    def f2(self): ...
Run Code Online (Sandbox Code Playgroud)

要自动将装饰器应用于所有方法,您可以使用yet-another-decorator,这次,装饰类:

import inspect
def decorate_all_methods(decorator):
    def apply_decorator(cls):
        for k, f in cls.__dict__.items():
            if inspect.isfunction(f):
                setattr(cls, k, decorator(f))
        return cls
    return apply_decorator
Run Code Online (Sandbox Code Playgroud)

并像这样申请:

@decorate_all_methods(Http500Resistant)
class A(object):
    ...
Run Code Online (Sandbox Code Playgroud)

或者像:

class A(object): ...
A = decorate_all_methods(Http500Resistant)(A)
Run Code Online (Sandbox Code Playgroud)