在学习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.
看了这个我还是没懂书中的代码为什么要这样= =。。。
The key to this question lies in the third sentence from the bottom:
Because a separate thread is opened here, you may be wondering why the implementation of
current_app
了?对!就是开了一个线程就不能使用current_app
。原因在于current_app
cannot be used when a thread is opened.current_app
在Flask
是一个代理,如果你看Flask
If you look at the source code, you will find that it is actually wrapped like this:Source code address line: 48-58
The function of this
LocalProxy
就不展开讲了,但是我可以告诉你这个LocalProxy
is to return the object corresponding to the current coroutine/thread according to the thread/coroutine, that is to sayThread A inserts A into LocalProxy
Thread B inserts B into LocalProxy
No matter where you are,
Thread A will always get A, thread B will always get B
This is the underlying reason for variables like
Flask
中可以在代码中直接使用request
、current_app
.So, here comes the answer, because a new thread is opened here, if you don't pass through the real object, then you use
current_app
将获取不到对象,因为他没有flask 上下文
inside the thread. This is another important concept of Flask, there is too much to say.You can probably say this, and the questioner should be able to understand it.
I saw this code at the time and thought it was the same, but why not app=current_object?
So take another look. My point is that the description in the document mentions that current_app is a global application object, and current_app._get_current_object is a get object (get an object), similar to the staticmethod and class below. classmethod corresponds to different things (this analogy is not accurate, but it is not difficult to get what I mean, they are essentially very similar).
Look at the explanation of this answer:
However, it is wrong to say this, look at the explanation of _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.
What is written here is real object
Does this mean that this is an instance? It can be understood this way, and of course it can be more accurate.
Because no matter what, it’s better to look at the source code, because it doesn’t matter what it is. The person who designed the framework can write it in reverse and convert it
Whether it is an instance or an object, their methods will definitely be different. After all, the code is human Designed, this framework is also written by people. It has more to do with the framework itself. There is no more meaning in being too obsessed with objects or instances, because I guess in the end it is neither.