在学习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.
看了这个我还是没懂书中的代码为什么要这样= =。。。
この質問の鍵は下から 3 番目の文にあります:
リーリーここで別のスレッドが開かれるのに、なぜスレッドを開いた後に
current_app
を使用できないのかと疑問に思われるかもしれません。右!スレッドを開くだけではcurrent_app
は使用できません。その理由はcurrent_app
の実装にあります。
リーリーcurrent_app
はFlask
のプロキシです。Flask
のソース コードを見ると、実際には次のようにラップされていることがわかります:ソース コード アドレス行: 48-58
この
と言うLocalProxy
については詳しく説明しませんが、このLocalProxy
の機能は、スレッド/コルーチンに従って、現在のコルーチン/スレッドに対応するオブジェクトを返すことであると言えます。スレッド A が A
スレッド B が B を LocalProxy に挿入します
どこにいても、
スレッド A は常に A を取得し、スレッド B は常に B を取得します
これが、
Flask
やrequest
のような変数をcurrent_app
のコード内で直接使用できる根本的な理由です。これが答えです。ここで新しいスレッドが開かれるため、実際のオブジェクトを通過しない場合、スレッド内で
current_app
を使用してもオブジェクトを取得できません。flask 上下文
がありません。これは Flask のもう 1 つの重要なコンセプトであり、言うことは多すぎます。質問者さんなら理解できるはずだと言えます。
当時このコードを見て同じだと思いましたが、なぜ app=current_object ではないのでしょうか?
それでは、もう一度見てください。私の言いたいことは、ドキュメント内の説明では、current_app がグローバル アプリケーション オブジェクトであり、current_app._get_current_object が get オブジェクト (オブジェクトの取得) であり、次のクラス Staticmethod と classmethod が対応するのと同様であるということです。異なるものです (この例えは正確ではありませんが、私が言いたいことを理解するのは難しくありません。本質的には非常に似ています)。
この回答の説明を見てください:
しかし、これを言うのは間違いです。_get_current_object
の説明を見てください。現在のオブジェクトを返します。これは、パフォーマンス上の理由から、またはオブジェクトを別のコンテキストに渡したい場合に、一度にプロキシの背後にある実際のオブジェクトが必要な場合に便利です。
ここに書いてあるのは実体です
これはインスタンスということですか?このように理解することもできますし、もちろん、より正確にすることもできます。
それがインスタンスであろうと、フレームワークを設計した人がそれを逆に書くことで変換できるので、何にしてもソースコードを見たほうが良いです。結局のところ、コードは人によって設計され、このフレームワークも人によって書かれます。あまりにもこだわることには意味がありません。オブジェクトかインスタンスか、最終的にはどちらでもないと思います。