【问题标题】:What object EXACTLY is returned by session._get_current_object()?session._get_current_object() 究竟返回了什么对象?
【发布时间】:2019-04-23 07:11:30
【问题描述】:

我正在玩 Flask,努力了解会话如何工作的细节,我正在使用:

  • Python 3.6.1
  • 烧瓶 0.12.2

Flask 文档clearly states粗体字是我的):

会话对象的工作方式与普通的字典非常相似,带有 区别在于它会跟踪修改。

这是一个代理

...

Section on proxies 提到(再次,粗体是我的):

如果您需要访问 对于被代理的底层对象,您可以使用 _get_current_object()方法

因此,对于请求,底层对象 (session._get_current_object()) 必须保持不变,或者正如 this answer and comment 所建议的那样,一个线程。但是,它不会持续存在,也不会在请求内部,也不会在线程中。

这是一个演示代码:

import threading

    from flask import (
    Flask,
    session,
    )

    app = Flask(__name__)
    app.secret_key = 'some random secret key'

    @app.route('/')
    def index():
        print("session ID is: {}".format(id(session)))
        print("session._get_current_object() ID is: {}".format(id(session._get_current_object())))
        print("threading.current_thread().ident is: {}".format(threading.current_thread().ident))
        print('________________________________')
        return 'Check the console! ;-)'

如果您将运行上面的 Flask 应用程序,并反复访问 /session._get_current_object() 返回的 id 偶尔会改变,而 threading.current_thread().ident 永远不会改变。

这导致我提出以下问题:

  1. session._get_current_object() 返回的究竟是什么?
  2. 我知道它是 session 代理的底层对象,但这个底层对象绑定到什么(如果它不是请求而不是线程,如果有的话,我希望它永远不会改变,对于简单的应用程序以上)?

【问题讨论】:

标签: python flask


【解决方案1】:

session._get_current_object() 究竟返回了什么?

从技术上讲,它是在名为_request_ctx_stackLocalStack 实例的最顶层元素的session 属性中引用的对象。
该堆栈的最顶层元素是RequestContext,它在Flask.wsgi_app 中被实例化,每个HTTP 请求都会调用它。
RequestContext 实现pushpop 自身往返的方法本地堆栈_request_ctx_stackpush 方法还负责处理上下文的 requesting a new session

此会话是在session 代理中提供的;初始化RequestContext 的请求可通过request 代理获得。这两个代理只能在请求上下文中使用,即处理活动的 HTTP 请求。

我知道它是一个底层会话代理的对象,但是这是什么 底层对象绑定到(如果它不是请求而不是 线程,如果有什么我希望它永远不会改变,因为简单 上面的应用程序)?

如上所述,由session 本地代理代理的请求上下文会话属于RequestContext。它随着每个请求而变化。如Lifetime of the Context 中所述,为每个请求创建一个新上下文,并且每次执行push 时都会创建一个新会话。

session._get_current_object() 的 id 在连续请求之间保持不变可能是因为新会话对象创建在与前一个请求的旧会话对象相同的内存地址中。

另请参阅:Flask 文档的How the Context Works 部分。

【讨论】:

  • 我很欣赏如此详尽的解释!
【解决方案2】:

这里是修改后的代码sn-p,用来说明answer by shmee

import threading

from flask import (
Flask,
session,
request
)

app = Flask(__name__)
app.secret_key = 'some random secret key'

@app.route('/')
def index():
    print(">>> session <<<")
    session_id = id(session)
    session_object_id = id(session._get_current_object())
    print("ID: {}".format(session_id),
          "Same as previous: {}".format(session.get('prev_sess_id', '') == session_id))
    print("_get_current_object() ID: {}".format(session_object_id),
          "Same as previous: {}".format(session.get('prev_sess_obj_id', '') == session_object_id))
    session['prev_sess_id'] = session_id
    session['prev_sess_obj_id'] = session_object_id

    print("\n>>> request <<<")
    request_id = id(request)
    request_object_id = id(request._get_current_object())
    print("request ID is: {}".format(request_id),
          "Same as previous: {}".format(session.get('prev_request_id', '') == request_id))
    print("request._get_current_object() ID is: {}".format(id(request._get_current_object())),
          "Same as previous: {}".format(session.get('prev_request_obj_id', '') == request_object_id))
    session['prev_request_id'] = request_id
    session['prev_request_obj_id'] = request_object_id

    print("\n>>> thread <<<")
    thread_id = threading.current_thread().ident
    print("threading.current_thread().ident is: {}".format(threading.current_thread().ident),
          "Same as previous: {}".format(session.get('prev_thread', '') == thread_id))
    session['prev_thread'] = thread_id
    print('-' * 100)
    return 'Check the console! ;-)'

确实,剩下的唯一模糊之处是为什么有时 session._get_current_object() 在连续请求之间保持不变。正如shmee 所建议的那样(粗体字是我的),它是:

可能,因为新会话对象创建在与前一个请求中的旧会话对象所占用的内存地址相同的内存地址中。

【讨论】:

    猜你喜欢
    • 2011-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-11
    • 2017-05-06
    • 2016-04-21
    • 2013-06-30
    相关资源
    最近更新 更多