关于python:如何捕获装饰器中引发的错误?

How do I catch an error raised in a decorator?

我正在使用flask auth,它提供一些辅助装饰器。我已经在下面添加了所有不同的方法,但我想问的问题是如何捕获authorized_handler装饰器抛出的任何问题。这是一个关于装饰师的一般性问题,但我认为一个真正的例子可能会有所帮助。

如果装饰师爆炸了,我怎么能抓住它?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import os
import flask
import flask_oauth

CONSUMER_KEY = os.environ['CONSUMER_KEY']
CONSUMER_SECRET = os.environ['CONSUMER_SECRET']

oauth = flask_oauth.OAuth()
twitter = oauth.remote_app(
    'twitter',
    base_url='https://api.twitter.com/1/',
    request_token_url='https://api.twitter.com/oauth/request_token',
    access_token_url='https://api.twitter.com/oauth/access_token',
    authorize_url='https://api.twitter.com/oauth/authenticate',
    consumer_key=CONSUMER_KEY,
    consumer_secret=CONSUMER_SECRET
)

app = flask.Flask(__name__)

@app.route('/login')
def login():
    return twitter.authorize(
        callback=url_for(
            'oauth_authorized',
            next=request.args.get('next') or request.referrer or None)
    )

@app.route('/oauth-authorized')
# what happens if this raises an error?
@twitter.authorized_handler
def oauth_authorized(resp):
    print 'foo-bar'

执行函数定义。因此,假设引发的异常是特定于该修饰符的,则可以将函数定义(包括修饰符)包装在try/except中:

1
2
3
4
5
6
7
try:
    @app.route('/oauth-authorized')
    @twitter.authorized_handler
    def oauth_authorized(resp):
        print 'foo-bar'
except WhateverError as e:
    print"twitter.authorized_handler raised an error", e

当然,如果引发异常,这将使oauth_authorized未定义。在您的情况下,这可能是正常的,因为您可能不希望它被路由。但如果这不是您想要的,您可以向您的except块添加一个虚拟定义。

或者,由于decorator只是函数(好吧,任何可调用的),而@符号仅仅是函数调用的语法糖,所以您可以在try/except中包装authorized_handler装饰:

1
2
3
4
5
6
7
8
def oauth_authorized(resp):
    print 'foo-bar'
try:    # apply decorator
    oauth_authorized = twitter.authorized_handler(oauth_authorized)
except Exception as e:
    print"twitter.authorized_handler raised an error", e
else:   # no error decorating with authorized_handler, apply app.route
    oauth_authorized = app.route('/oauth-authorized')(oauth_authorized)

如果authorized_handler装饰失败,这将给您留下未修饰的函数版本,但它不会被路由。你甚至可以把上面的内容放到它自己的功能中,并把它作为一个装饰器使用!