> For the complete documentation index, see [llms.txt](https://flask-yushu.gitbook.io/yushu/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://flask-yushu.gitbook.io/yushu/11.python-yu-flask-de-jie-he-ying-yong/11.2-firstor404-he-ke-tiao-yong-dui-xiang.md).

# 11.2 first\_or\_404和可调用对象

## 1.first\_or\_404

视图函数接受用户填写的email账号，如果不存在应该跳转到404界面，这个逻辑flask-sqlalchemy为我们提供了良好的封装，不需要手动去处理,只需要调用Query的first\_or\_404()方法即可

```python
user = User.query.filter_by(email=account_email).first_or_404()
```

first\_or\_404内部是对first函数的封装，他在获取了first的结果以后，会进行空判断，如果结果为空，则调用abort()方法，而abort()方法内部是调用了一个对象

first\_or\_404

```python
    def first_or_404(self):
        """Like :meth:`first` but aborts with 404 if not found instead of returning ``None``."""

        rv = self.first()
        if rv is None:
            abort(404)
        return rv
```

abort()

```python
def abort(status, *args, **kwargs):
    '''
    Raises an :py:exc:`HTTPException` for the given status code or WSGI
    application::

        abort(404)  # 404 Not Found
        abort(Response('Hello World'))

    Can be passed a WSGI application or a status code.  If a status code is
    given it's looked up in the list of exceptions and will raise that
    exception, if passed a WSGI application it will wrap it in a proxy WSGI
    exception and raise that::

       abort(404)
       abort(Response('Hello World'))

    '''
    return _aborter(status, *args, **kwargs)

_aborter = Aborter()
```

如果要将一个对象像函数一样调用，需要在函数内部实现\_\_call\_\_方法，`_aborter(status, *args, **kwargs)`实际上就是调用了Aborter的\_\_call\_\_方法

Aborter()

```python
class Aborter(object):

    """
    When passed a dict of code -> exception items it can be used as
    callable that raises exceptions.  If the first argument to the
    callable is an integer it will be looked up in the mapping, if it's
    a WSGI application it will be raised in a proxy exception.

    The rest of the arguments are forwarded to the exception constructor.
    """

    def __init__(self, mapping=None, extra=None):
        if mapping is None:
            mapping = default_exceptions
        self.mapping = dict(mapping)
        if extra is not None:
            self.mapping.update(extra)

    def __call__(self, code, *args, **kwargs):
        if not args and not kwargs and not isinstance(code, integer_types):
            raise HTTPException(response=code)
        if code not in self.mapping:
            raise LookupError('no exception for %r' % code)
        raise self.mapping[code](*args, **kwargs)
```

## 2.可调用对象的作用

![image.png](https://upload-images.jianshu.io/upload_images/7220971-42d1552795e1e2c2.png?imageMogr2/auto-orient/strip|imageView2/2/w/1240) 关于其中的统一调用接口，我们看下面的实例

```python
class A:
    def go(self):
        return object()


class B:
    def run(self):
        return object()


def func():
    return object()


def main(param):
    # 我想在main中传入一个参数，得到一个对象object
    # b.run()
    # a.go()
    # func()
    pass


main(A())
main(B())
main(func)
```

如果不适用可调用对象，我们需要在main函数中区分是不同的情况，分别处理，非常的麻烦。 如果main方法传入的参数只有方法那就好说了，我们只需要`param()`就可以调用，所以python为我们提供了可调用对象，让对象可以像方法一样调用,修改好的代码如下

```python
class A:
    def __call__(self):
        return object()


class B:
    def __call__(self):
        return object()


def func():
    return object()


def main(callable):
    # 我想在main中传入一个参数，得到一个对象object
    callable()
    pass


main(A())
main(B())
main(func)
```

这就是可调用对象中统一调用接口的意义。在flask中有很多可调用对象的使用，如globas.py中对current\_app,request等对象的封装.其中\_find\_app，\_lookup\_req\_object都是可调用对象

```python
# context locals
_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()
current_app = LocalProxy(_find_app)
request = LocalProxy(partial(_lookup_req_object, 'request'))
session = LocalProxy(partial(_lookup_req_object, 'session'))
g = LocalProxy(partial(_lookup_app_object, 'g'))
```
