python - flask中current_app._get_current_object()与current_app有什么区别?

 书友73892718 发布于 2022-10-30 16:44

在学习flask开发,书中一段异步发送邮件的代码是这样写的:

from threading import Thread
from flask import current_app, render_template
from flask.ext.mail import Message
from . import mail


def send_async_email(app, msg):
    with app.app_context():
        mail.send(msg)


def send_email(to, subject, template, **kwargs):
    app = current_app._get_current_object()
    msg = Message(app.config['FLASKY_MAIL_SUBJECT_PREFIX'] + ' ' + subject,
                  sender=app.config['FLASKY_MAIL_SENDER'], recipients=[to])
    msg.body = render_template(template + '.txt', **kwargs)
    msg.html = render_template(template + '.html', **kwargs)
    thr = Thread(target=send_async_email, args=[app, msg])
    thr.start()
    return thr

send_mail函数中,程序使用了current_app._get_current_object()赋值给app作为当前程序的实例。此处为什么不直接使用current_app呢?

flask官方文档中是这样解释这个方法_get_current_object()的:

Return the current object. This is useful if you want the real object behind the proxy at a time for performance reasons or because you want to pass the object into a different context.

看了这个我还是没懂书中的代码为什么要这样= =。。。

2 个回答
  • 我当时看到过这个代码,原觉得是一样的,但为什么不可以app=current_object呢?

    所以再看一看,我的观点是,文档里描述提到了current_app是一个全局的对象(global application object),而current_app._get_current_object是获取对(get an object)象,类似于class下面的staticmethod和classmethod对应的是不同的东西(这个类比不准确,但不难get到我的意思,本质上有很类似之处)。

    看看这个回答的解释:

    然而这么说也是不对的,看看对_get_current_object的解释

    Return the current object. This is useful if you want the real object behind the proxy at a time for performance reasons or because you want to pass the object into a different context.

    这里写的是real object
    这么是否是说这是一个实例?可以这么理解,当然可以更加准确。

    因为无论如何,还是去看源代码,因为是什么不重要,设计框架的人反过来写就能换转了
    无论是实例还是对象,它们的方法等肯定会有所差异,毕竟代码是人设计的,这个框架也是人写的,这里更多与框架本身有关,过多执着于对象还是实例没有更多的意义,因为我猜到头来两者都不是。

    2022-10-31 21:56 回答
  • 这个问题的关键在倒数的第三句:

    thr = Thread(target=send_async_email, args=[app, msg])

    因为这里开了一个单独的线程,也许你会奇怪了,凭什么开了一个线程就不能使用 current_app 了?对!就是开了一个线程就不能使用 current_app。原因在于 current_app 的实现。

    current_appFlask 是一个代理,如果你看 Flask 源码的话会发现其实它外部包裹的是这样的:
    源码地址 line: 48-58

    def _find_app():
        top = _app_ctx_stack.top
        if top is None:
            raise RuntimeError(_app_ctx_err_msg)
        return top.app
    
    ...
    
    current_app = LocalProxy(_find_app)

    这个 LocalProxy 就不展开讲了,但是我可以告诉你这个LocalProxy 的作用就是可以根据线程/协程返回对应当前协程/线程的对象,也就是说

    • 线程 A 往 LocalProxy 中塞入 A

    • 线程 B 往 LocalProxy 中塞入 B

    无论在是什么地方,

    • 线程 A 永远取到得是 A,线程 B 取到得永远是 B

    这就是在 Flask 中可以在代码中直接使用 requestcurrent_app 这样的变量的底层原因。

    所以,答案来了,因为这里开了一个新线程,如果你不穿真实对象过去,那么你在线程里面使用 current_app 将获取不到对象,因为他没有 flask 上下文。这又是一个 Flask 的重要概念,太多得说。

    大概可以这样说,题主应该可以理解吧。

    2022-10-31 21:56 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有