Python 如果decorator函数在库中,我可以';不能修改吗?

Python 如果decorator函数在库中,我可以';不能修改吗?,python,sockets,google-app-engine,decorator,statsd,Python,Sockets,Google App Engine,Decorator,Statsd,我正在谷歌应用程序引擎(GAE)上工作。不幸的是,GAE在使用套接字时会不时引发ApplicationError:4未知错误。。该错误是一个apiproxy\u错误。ApplicationError statsd客户端已设置为捕获套接字的socket.error,但未捕获套接字在GAE上可能引发的ApplicationError 我专门使用timer,它返回timer的一个实例: Timer的\uuuu调用\uuu方法允许将其用作装饰器,如下所示: from statsd import Sta

我正在谷歌应用程序引擎(GAE)上工作。不幸的是,GAE在使用套接字时会不时引发
ApplicationError:4未知错误。
。该错误是一个
apiproxy\u错误。ApplicationError

statsd客户端已设置为捕获套接字的
socket.error
,但未捕获套接字在GAE上可能引发的
ApplicationError

我专门使用
timer
,它返回
timer
的一个实例:

Timer
\uuuu调用\uuu
方法允许将其用作装饰器,如下所示:

from statsd import StatsClient statsd = StatsClient() @statsd.timer('myfunc') def myfunc(a, b): """Calculate the most complicated thing a and b can do.""" 然后将使用如下方式:

@my_timer_wrapper('stastd_timer_name') def timed_func(): do_work() @我的定时器包装器('stastd定时器名称') def timed_func(): 你工作吗
有更好的或更具python风格的方法吗?

看起来这是一个“尽可能简单”的例子 新的装饰器在计时器装饰器周围添加了额外的try/except

唯一的问题是接受参数的decorator需要 要定义的嵌套函数的两个级别,几乎总是使它们 看起来很复杂,即使它们不是:

from functools import wraps

def  shielded_timer(statsd, 
                    exceptions=(apiproxy_errors.ApplicationError),
                    name=None):

    def decorator(func):
        timer_decorator = statsd.timer(name or func.__name__)
        new_func = timer_decorator(func)
        @wraps(func)
        def wrapper(*args, **kw):
            try:
                return new_func(*args, **kw)
            except BaseException as error:
                if isinstance (error, exceptions):
                    # Expected error (ApplicationError by default) ocurred
                    pass
                else:
                    raise
        return wrapper
    return decorator



#####################
statsd = StatsClient()
@shielded_timer(statsd)
def my_func(a,b):
    ...
正如您所看到的,甚至包括额外的细节都很容易——在本例中,我已经在装饰时配置了想要的异常,并且还可以选择在
调用statsd.timer。

看起来该类可以用作上下文管理器,这将更容易包装在try/except中。您可以直接使用monkey补丁statsd。在appengine_config.py中执行补丁,这样在代码库中只需要执行一次。
from functools import wraps

def  shielded_timer(statsd, 
                    exceptions=(apiproxy_errors.ApplicationError),
                    name=None):

    def decorator(func):
        timer_decorator = statsd.timer(name or func.__name__)
        new_func = timer_decorator(func)
        @wraps(func)
        def wrapper(*args, **kw):
            try:
                return new_func(*args, **kw)
            except BaseException as error:
                if isinstance (error, exceptions):
                    # Expected error (ApplicationError by default) ocurred
                    pass
                else:
                    raise
        return wrapper
    return decorator



#####################
statsd = StatsClient()
@shielded_timer(statsd)
def my_func(a,b):
    ...