flask:RuntimeError: Working outside of application context.

新建测试文件

from flask import Flask,current_app

app = Flask(__name__)

a = current_app
b = current_app.config['DEBUG']

if __name__=='__main__':
    app.run(debug=True)

当运行文件时会报错:
RuntimeError: Working outside of application context.

查看current_app源码

# 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'))

'''
current_app,request,session三者都是localProxy对象
'''

查看localProxy源码

@implements_bool
class LocalProxy(object):
    __slots__ = ('__local', '__dict__', '__name__', '__wrapped__')

    def __init__(self, local, name=None):
        object.__setattr__(self, '_LocalProxy__local', local)
        object.__setattr__(self, '__name__', name)
        if callable(local) and not hasattr(local, '__release_local__'):
            # "local" is a callable that is not an instance of Local or
            # LocalManager: mark it as a wrapped function.
            object.__setattr__(self, '__wrapped__', local)

    def _get_current_object(self):
        if not hasattr(self.__local, '__release_local__'):
            return self.__local()
        try:
            return getattr(self.__local, self.__name__)
        except AttributeError:
            raise RuntimeError('no object bound to %s' % self.__name__)

    @property
    def __dict__(self):
        try:
            return self._get_current_object().__dict__
        except RuntimeError:
            raise AttributeError('__dict__')

    def __repr__(self):
        try:
            obj = self._get_current_object()
        except RuntimeError:
            return '<%s unbound>' % self.__class__.__name__
        return repr(obj)

    def __bool__(self):
        try:
            return bool(self._get_current_object())
        except RuntimeError:
            return False

    def __unicode__(self):
        try:
            return unicode(self._get_current_object())  # noqa
        except RuntimeError:
            return repr(self)

    def __dir__(self):
        try:
            return dir(self._get_current_object())
        except RuntimeError:
            return []

    def __getattr__(self, name):
        if name == '__members__':
            return dir(self._get_current_object())
        return getattr(self._get_current_object(), name)

    def __setitem__(self, key, value):
        self._get_current_object()[key] = value

    def __delitem__(self, key):
        del self._get_current_object()[key]

    if PY2:
        __getslice__ = lambda x, i, j: x._get_current_object()[i:j]

        def __setslice__(self, i, j, seq):
            self._get_current_object()[i:j] = seq

        def __delslice__(self, i, j):
            del self._get_current_object()[i:j]

    __setattr__ = lambda x, n, v: setattr(x._get_current_object(), n, v)
    __delattr__ = lambda x, n: delattr(x._get_current_object(), n)
    __str__ = lambda x: str(x._get_current_object())
    __lt__ = lambda x, o: x._get_current_object() < o
    __le__ = lambda x, o: x._get_current_object() <= o
    __eq__ = lambda x, o: x._get_current_object() == o
    __ne__ = lambda x, o: x._get_current_object() != o
    __gt__ = lambda x, o: x._get_current_object() > o
    __ge__ = lambda x, o: x._get_current_object() >= o
    __cmp__ = lambda x, o: cmp(x._get_current_object(), o)  # noqa
    __hash__ = lambda x: hash(x._get_current_object())
    __call__ = lambda x, *a, **kw: x._get_current_object()(*a, **kw)
    __len__ = lambda x: len(x._get_current_object())
    __getitem__ = lambda x, i: x._get_current_object()[i]
    __iter__ = lambda x: iter(x._get_current_object())
    __contains__ = lambda x, i: i in x._get_current_object()
    __add__ = lambda x, o: x._get_current_object() + o
    __sub__ = lambda x, o: x._get_current_object() - o
    __mul__ = lambda x, o: x._get_current_object() * o
    __floordiv__ = lambda x, o: x._get_current_object() // o
    __mod__ = lambda x, o: x._get_current_object() % o
    __divmod__ = lambda x, o: x._get_current_object().__divmod__(o)
    __pow__ = lambda x, o: x._get_current_object() ** o
    __lshift__ = lambda x, o: x._get_current_object() << o
    __rshift__ = lambda x, o: x._get_current_object() >> o
    __and__ = lambda x, o: x._get_current_object() & o
    __xor__ = lambda x, o: x._get_current_object() ^ o
    __or__ = lambda x, o: x._get_current_object() | o
    __div__ = lambda x, o: x._get_current_object().__div__(o)
    __truediv__ = lambda x, o: x._get_current_object().__truediv__(o)
    __neg__ = lambda x: -(x._get_current_object())
    __pos__ = lambda x: +(x._get_current_object())
    __abs__ = lambda x: abs(x._get_current_object())
    __invert__ = lambda x: ~(x._get_current_object())
    __complex__ = lambda x: complex(x._get_current_object())
    __int__ = lambda x: int(x._get_current_object())
    __long__ = lambda x: long(x._get_current_object())  # noqa
    __float__ = lambda x: float(x._get_current_object())
    __oct__ = lambda x: oct(x._get_current_object())
    __hex__ = lambda x: hex(x._get_current_object())
    __index__ = lambda x: x._get_current_object().__index__()
    __coerce__ = lambda x, o: x._get_current_object().__coerce__(x, o)
    __enter__ = lambda x: x._get_current_object().__enter__()
    __exit__ = lambda x, *a, **kw: x._get_current_object().__exit__(*a, **kw)
    __radd__ = lambda x, o: o + x._get_current_object()
    __rsub__ = lambda x, o: o - x._get_current_object()
    __rmul__ = lambda x, o: o * x._get_current_object()
    __rdiv__ = lambda x, o: o / x._get_current_object()
    if PY2:
        __rtruediv__ = lambda x, o: x._get_current_object().__rtruediv__(o)
    else:
        __rtruediv__ = __rdiv__
    __rfloordiv__ = lambda x, o: o // x._get_current_object()
    __rmod__ = lambda x, o: o % x._get_current_object()
    __rdivmod__ = lambda x, o: x._get_current_object().__rdivmod__(o)
    __copy__ = lambda x: copy.copy(x._get_current_object())
    __deepcopy__ = lambda x, memo: copy.deepcopy(x._get_current_object(), memo)

探究以下问题
AppContext、RequestContext、Flask与Request之间的关系

  • flask中上下文机制:
    flask中上下文是一种对象
'''
     *应用上下文: 对象   Flask*
     *请求上下文: 对象   Request*
     Flask  --> Appcontext
    Request --> RequestContext
'''
#Appcontext是对Flask的封装,将Flask的外部操作封装到Appcontext对象中
#Request同上

通过
from flask import current_app,request
实际是通过LocalProxy方法找到flask核心对象和Request类

flask核心机制图解

这里写图片描述

 flask实现栈的对象是LocalStack
 falsk实例化两个栈:
     _app_ctx_stack = LocalStack()
     _request_ctx_stack = LocalStack()
当请求进入时,RequestContext先被实例化,实例化后推入_reuqest_ctx_stack栈中,此时flask会检测_app_ctx_stack栈顶是否为空,如果为空flask会将当前应用对象AppContext实例化后推入_app_ctx_stack栈顶

current_app=LoaclProxy(find_app)中find_app源码如下:

def _find_app():
    #取栈顶对象
    top = _app_ctx_stack.top
    if top is None:
        raise RuntimeError(_app_ctx_err_msg)
    #返回栈顶AppContext中的app对象
    return top.app

此时current_app返回应用上下文AppContext中app对象

request=LocalProxy(partial(_lookup_req_object,’request’))
中_lookup_req_objext源码如下:

def _lookup_req_object(name):
    #获取request栈顶对象
    top = _request_ctx_stack.top
    if top is None:
        raise RuntimeError(_request_ctx_err_msg)
    #返回栈顶对象的name
    return getattr(top, name)

current_app和request永远指向两个栈的栈顶对象
以上可看出,当请求通过flask访问时,会先生成Request请求上下文对象的实例化,并通过request代理指向request对象。然后由flask来实例化AppContext 对象,并推入栈中,从而让current_app有指向对象
当进行离线应用、单元测试时,因为没有触发request请求,需要自行将应用上下文推入栈中。再手动弹出

from flask import current_app,request

app = Flask(__name__)

ctx = app.app_context()
ctx.push()
a = current_app
curent_app.config['DEBUG']
ctx.pop()
python中优化写法,使用with语句
* 使用了上下文协议的对象使用with
* 上下文管理器
* __enter__ __exit__
* 上下文表达式必须要返回一个上下文管理器

例如:文件读写

with open('/2.txt') as f:
    f.read()
#f是__enter__方法的返回值

flask优化改写:

from flask import Flask,current_app

app = Flask(__name__)

with app.app_context():
    a = current_app
    b = current_app.config['DEBUG']
'''
app_context()方法返回一个AppContext应用上下文管理器
在AppContext中定义了__enter__和__exit__方法
'''

Appcontext中上下文管理器部分源码:

    def __enter__(self):
        self.push()
        return self

    def __exit__(self, exc_type, exc_value, tb):
        self.pop(exc_value)

因此在with语句中,AppContext中定义了__exit__方法,所以当current_app离开with语句中时,_app_ctx_stack栈顶的AppContext已被弹出,current_app没有任何指向对象。

猜你喜欢

转载自blog.csdn.net/weixin_35993084/article/details/80609131