引出的问题

Flask如何使用上下文临时把某些对象变为全局可访问

首先我们做如下的几种情况的假设

情况一:单进程单线程

这种情况可以基于全局变量存储临时的对象

情况二:单进程多线程

这种情况会出现多个线程共享全局的变量,为了每个线程中的数据不被其他线程修改,可以借助hreading.local对象,为每个线程做唯一的表示用来做键,请求的对象作为值来实现

多线程共享数据的问题

import threading
class Foo(object):
def __init__(self):
self.name = 0 local_values = Foo() def func(num):
local_values.name = num
import time
time.sleep(1)
print(local_values.name, threading.current_thread().name) for i in range(20):
th = threading.Thread(target=func, args=(i,), name='线程%s' % i)
th.start()

我们可以看到最后把每个线程中对象中name值都变为了19,不能保证每个线程中对象中的值唯一

使用hreading.local对象可以对每个线程做唯一的表示可以解决上述的问题

import threading

local_values = threading.local()

def func(num):
local_values.name = num
import time
time.sleep(1)
print(local_values.name, threading.current_thread().name) for i in range(20):
th = threading.Thread(target=func, args=(i,), name='线程%s' % i)
th.start()

可以看到每个线程中的值唯一

- 情况三:单进程单线程(多个协程)Flask 的上下文管理就是基于这种情况做的

在这种情况下使用上面的方法可以保证线程中的数据唯一,但是使用其内部创建多个协程后,hreading.local只能对线程作唯一的标示,协程是在单线程下切换的,所以多个协程还会出现共享数据的问题

解决的思路:为每个程做唯一的标示,我们可以通过python自带的greenlet模块中的getcurrent来实现

只需对上面的代码做简单的修改即可

import threading
try:
from greenlet import getcurrent as get_ident # 协程
except ImportError:
try:
from thread import get_ident
except ImportError:
from _thread import get_ident # 线程 class Local(object):
def __init__(self):
self.storage = {}
self.get_ident = get_ident def set(self,k,v):
ident = self.get_ident()
origin = self.storage.get(ident)
if not origin:
origin = {k:v}
else:
origin[k] = v
self.storage[ident] = origin def get(self,k):
ident = self.get_ident()
origin = self.storage.get(ident)
if not origin:
return None
return origin.get(k,None) local_values = Local() def task(num):
local_values.set('name',num)
import time
time.sleep(1)
print(local_values.get('name'), threading.current_thread().name) for i in range(20):
th = threading.Thread(target=task, args=(i,),name='线程%s' % i)
th.start()

测试的结果如下

使用面向对象中方法对其进行简单的优化

在初始化的时候设置属性的时候,为了避免循环引用,我们可以这样做  object.__setattr__(self, 'storage', {})

class Foo(object):

    def __init__(self):
object.__setattr__(self, 'storage', {})
# self.storage = {} def __setattr__(self, key, value):
self.storage = {'k1':'v1'}
print(key,value) def __getattr__(self, item):
print(item)
return 'df' obj = Foo() # obj.x = 123
# 对象.xx

修改后的代码如下所示

import threading
try:
from greenlet import getcurrent as get_ident # 协程
except ImportError:
try:
from thread import get_ident
except ImportError:
from _thread import get_ident # 线程 class Local(object): def __init__(self):
object.__setattr__(self, '__storage__', {})
object.__setattr__(self, '__ident_func__', get_ident) def __getattr__(self, name):
try:
return self.__storage__[self.__ident_func__()][name]
except KeyError:
raise AttributeError(name) def __setattr__(self, name, value):
ident = self.__ident_func__()
storage = self.__storage__
try:
storage[ident][name] = value
except KeyError:
storage[ident] = {name: value} def __delattr__(self, name):
try:
del self.__storage__[self.__ident_func__()][name]
except KeyError:
raise AttributeError(name) local_values = Local() def task(num):
local_values.name = num
import time
time.sleep(1)
print(local_values.name, threading.current_thread().name) for i in range(20):
th = threading.Thread(target=task, args=(i,),name='线程%s' % i)
th.start()

偏函数 (帮助我们传递参数)

import functools

def func(a1):
print(a1) new_func = functools.partial(func,666) new_func() 

运行结果如下

面向对象中的魔法方法的简单使用

import flask.globals
class Foo(object): def __init__(self,num):
self.num = num def __add__(self, other):
data = self.num + other.num
return Foo(data) obj1 = Foo(11)
obj2 = Foo(22) v = obj1 + obj2
print(v.num)  

运行结果如下

chain 帮助我们拼接列表中的值

from itertools import chain

# def f1(x):
# return x + 1
#
# func1_list = [f1,lambda x:x-1]
#
# def f2(x):
# return x + 10
#
#
# new_fun_list = chain([f2],func1_list)
# for func in new_fun_list:
# print(func) v1 = [11,22,33]
v2 = [44,55,66] new = chain(v1,v2)
for item in new:
print(item)  

测试结果如下

Flask上下文源码分析

Flask中有两种上下文,请求上下文和应用上下文。

Flask上下文大致可以分为3个步奏

  1 请求到来的时候(为每个线程/协程开辟独立的空间,存入statck中)   

    - ctx = 封装RequestContext(request,session) 

   - ctx放到Local中

  2 执行视图函数的时候(调用每个线程自己的数据)

    - 导入request
    - 调用 _lookup_req_object函数:去local中将requestContext想获取到,再去requestContext中获取request或session

  3- 请求结束(把数据从stack中删除)

    - ctx.auto_pop()    

    - ctx从local中移除。

当程序启动时执行run方法中的 run_simple方法

请求上下文  (request,session)

封装请求相关的数据

    def run(self, host=None, port=None, debug=None,
load_dotenv=True, **options): _host = '127.0.0.1'
_port = 5000
server_name = self.config.get('SERVER_NAME')
sn_host, sn_port = None, None if server_name:
sn_host, _, sn_port = server_name.partition(':') host = host or sn_host or _host
port = int(port or sn_port or _port) options.setdefault('use_reloader', self.debug)
options.setdefault('use_debugger', self.debug)
options.setdefault('threaded', True) cli.show_server_banner(self.env, self.debug, self.name, False) from werkzeug.serving import run_simple try:
run_simple(host, port, self, **options)
finally:
# reset the first request information if the development server
# reset normally. This makes it possible to restart the server
# without reloader and that stuff from an interactive shell.
self._got_first_request = False

当请求来的时候会执行 run_simple中的self对象,也就是app.__call__方法,代码如下

    def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response)

查看源码中的wsgi_app方法,参数environ表示所有请求的数据,start_response表示响应

    def wsgi_app(self, environ, start_response):
# 将请求相关的数据environ 封装到request_context 对象中
ctx = self.request_context(environ) # 生成一个类
error = None
try:
try:
# 把请求的对象封装到local中,每个线程 / 协程都是独立的空间存储
ctx.push()
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
except:
error = sys.exc_info()[1]
raise
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
# 最后把请求在local中的数据删掉
ctx.auto_pop(error)

在上面的源码中我们可以看到把所有请求相关的数据封装到了,self.request_context(environ)中,其返回一个RequestContext赋值给ctx我们继续追踪其内部的代码如下所示

    def request_context(self, environ):
     # self指的是app对象
return RequestContext(self, environ)

我们可以看到RequestContext类对environ进行了封装,在这里我们可以看到session的数据为None其初始化的方法如下:

class RequestContext(object):
def __init__(self, app, environ, request=None):
self.app = app
if request is None:
request = app.request_class(environ)
self.request = request
self.url_adapter = app.create_url_adapter(self.request)
self.flashes = None
self.session = None
self._after_request_functions = []
self.match_request()

把请求相关的数据添加到Local对象的storage中

我们继续追踪wsgi_app中的ctx.push的代码如下

    def push(self):
top = _request_ctx_stack.top
if top is not None and top.preserved:
top.pop(top._preserved_exc) app_ctx = _app_ctx_stack.top
if app_ctx is None or app_ctx.app != self.app:
app_ctx = self.app.app_context()
app_ctx.push()
self._implicit_app_ctx_stack.append(app_ctx)
else:
self._implicit_app_ctx_stack.append(None) if hasattr(sys, 'exc_clear'):
sys.exc_clear()
# self 是request_contenx的对象,其中包含了请求相关的所有数据
# _request_ctx_stack==>LocalStack
_request_ctx_stack.push(self) if self.session is None:
session_interface = self.app.session_interface
self.session = session_interface.open_session(
self.app, self.request
) if self.session is None:
self.session = session_interface.make_null_session(self.app)

在最下面我们看到了给session中的数据重新赋了值

我们查看_request_ctx_stack类和其内部的push方法,把请求封装后的数据_request_ctx当做参数传递进去

_request_ctx_stack = LocalStack()

  

继续追踪LocalStack类中的push方法代码如下

    def push(self, obj):
"""Pushes a new item to the stack"""
rv = getattr(self._local, 'stack', None)
if rv is None:
# 执行local 对象的__setatr__方法
self._local.stack = rv = []
# 把requestContext 对象添加到列表中 self._local.stack = rv = [把requestContext]
rv.append(obj)
return rv

在上面的源码中有一个赋值的操作self._local.stack=rv=[],self.local=local()会触发local()对象中的__setatr__方法参数key=stack,value=[],其__setatr__方法代码如下所示

    def __setattr__(self, name, value):
# name = stack value = []
# {"唯一的表示":
# {stack:[requestContext(ctx)]}
ident = self.__ident_func__()
storage = self.__storage__
try:
storage[ident][name] = value
except KeyError:
storage[ident] = {name: value}

ident = self.__ident_func__() 表示的是为线程/协程做唯一的标示,也就以为者当前的请求的上下文添加到了这样的一个字典中

继续追踪LocalStack类中的push方法中的下rv.append(obj),把当前请求相关的数据添加到stoage中,obj是请求相关的数据RequestCotent,

{
"线程/协助的唯一表示" : {"stack":["当前请求相关的数据"]} }

  

当请求结束的时候删除storage中的,当前请求的数据  

我们回去继续追踪wsgi_app中 ctx.auto_pop(error)方法删除请求结束后的数据

request和session使用内部调用源码分析

from flask import Flask,request  

其代码如下

from functools import partial
from werkzeug.local import LocalStack, LocalProxy def _lookup_req_object(name):
top = _request_ctx_stack.top
if top is None:
raise RuntimeError(_request_ctx_err_msg)
# 去requestContext中获取request的值
return getattr(top, name) def _lookup_app_object(name):
top = _app_ctx_stack.top
if top is None:
raise RuntimeError(_app_ctx_err_msg)
return getattr(top, name) def _find_app():
top = _app_ctx_stack.top
if top is None:
raise RuntimeError(_app_ctx_err_msg)
return top.app # context locals
_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()
current_app = LocalProxy(_find_app)
# partial 偏函数
request = LocalProxy(partial(_lookup_req_object, 'request'))
session = LocalProxy(partial(_lookup_req_object, 'session'))
g = LocalProxy(partial(_lookup_app_object, 'g'))

在上面的源码中,我们可以看到request是一个LocalProxy对象,其内部的参数通过偏函数partial调用_lookup_req_object函数传的参数默认为'request",_lookup_req_object代码如下

def _lookup_req_object(name):
top = _request_ctx_stack.top
if top is None:
raise RuntimeError(_request_ctx_err_msg)
# 去requestContext中获取request的值
return getattr(top, name)

top调用的是_app_ctx_stack= LocalStack()类中的top方法,代码如下

    def top(self):
"""The topmost item on the stack. If the stack is empty,
`None` is returned.
"""
try:
return self._local.stack[-1]
except (AttributeError, IndexError):
return None

其返回的是存储在storage{"stack":{"当前请求":[RequestContent(当前请求的数据)]}},中当前请求的数据,也就是RequestContent对象,所以上面的_llokup_req_object.函数返回的是RequestContent中的g

class RequestContext(object):

    def __init__(self, app, environ, request=None):
self.app = app
if request is None:
request = app.request_class(environ)
self.request = request
self.url_adapter = app.create_url_adapter(self.request)
self.flashes = None
self.session = None

所以request = LocalProxy(RequestContent.request)和session= LocalProxy(RequestContent.session)创建一个类,其初始化的方法如下

class LocalProxy(object):

    __slots__ = ('__local', '__dict__', '__name__', '__wrapped__')

    def __init__(self, local, name=None):
# self.__loacl = local local 指的是request
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)

通过上面的赋值我们可以知道,最终把RequestContent.reques赋值给self.local = RequestContent.reques

补充知识:面向对象的通过通过私有字段的取值

class Foo(object):

    def __init__(self):
self.name = 'alex'
self.__age = 18 def get_age(self):
return self.__age obj = Foo()
# 强制获取私有字段
print(obj._Foo__age)

当我们使用request中的方法的时候,会执行其内部的魔法方法如:

- print(request)   -->  LocalProxy对象的__str__
- request.method --> LocalProxy对象的__getattr__
- request + 1 --> LocalProxy对象的__add__

通过以上Flask源码的解读,我们可以试着传递一些值做一些简单的修改

from flask.globals import _request_ctx_stack
from functools import partial def _lookup_req_object(name):
# name = request
# top= ctx
top = _request_ctx_stack.top
if top is None:
raise RuntimeError('不存在')
# return ctx.request
return getattr(top, name) class Foo(object):
def __init__(self):
self.xxx = 123
self.ooo = 888 req = partial(_lookup_req_object,'xxx')
xxx = partial(_lookup_req_object,'ooo') # 当前求刚进来时
_request_ctx_stack.push(Foo()) # 使用
# obj = _request_ctx_stack.top
# obj.xxx
v1 = req()
print(v1)
v2 = xxx()
print(v2) # 请求终止,将local中的值移除
_request_ctx_stack.pop()

后台打印的结果如下

应用上下文(current__app,g)

源码wsgi_app

    def wsgi_app(self, environ, start_response):
# 将请求相关的数据environ 封装到request_context 对象中
# ctx.app = app
# ctx.request = app.request_class(environ)
ctx = self.request_context(environ) # 生成一个类
error = None
try:
try:
# 把请求的对象封装到local中,每个线程 / 协程都是独立的空间存储
ctx.push()
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
except:
error = sys.exc_info()[1]
raise
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
# 最后把请求在local中的数据删掉
ctx.auto_pop(error)

追踪ctx.push代码如下

    def push(self):
top = _request_ctx_stack.top
if top is not None and top.preserved:
top.pop(top._preserved_exc) app_ctx = _app_ctx_stack.top
if app_ctx is None or app_ctx.app != self.app:
# 应用上下文 创建一个对象 app_ctx = AppContext(object) app_ctx.g app_ctx.app
app_ctx = self.app.app_context()
app_ctx.push()
self._implicit_app_ctx_stack.append(app_ctx)
else:
self._implicit_app_ctx_stack.append(None) if hasattr(sys, 'exc_clear'):
sys.exc_clear()
# self 是request_contenx的对象,其中包含了请求相关的所有数据
# _request_ctx_stack==>LocalStack
_request_ctx_stack.push(self) if self.session is None:
        
session_interface = self.app.session_interface
self.session = session_interface.open_session(
self.app, self.request
) if self.session is None:
self.session = session_interface.make_null_session(self.app)

app_cxt = self.app.app_context() 的源码了解到其返回的是一个AppContext对象

    def app_context(self):
return AppContext(self)

AppContext源码如下

class AppContext(object):
def __init__(self, app):
self.app = app
self.url_adapter = app.create_url_adapter(None)
self.g = app.app_ctx_globals_class() # Like request context, app contexts can be pushed multiple times
# but there a basic "refcount" is enough to track them.
self._refcnt = 0

我们追踪g变量的源码发现其用法类似字典

class _AppCtxGlobals(object):

    def get(self, name, default=None):

        return self.__dict__.get(name, default)

    def pop(self, name, default=_sentinel):

        if default is _sentinel:
return self.__dict__.pop(name)
else:
return self.__dict__.pop(name, default) def setdefault(self, name, default=None): return self.__dict__.setdefault(name, default)

回到上面的代码  app_ctx对象,从中我们可以拿到app_ctx和app_ctx.app这就是我们要找的应用上下文了

继续追踪 app_ctx.push()源码如下

    def push(self):
self._refcnt += 1
if hasattr(sys, 'exc_clear'):
sys.exc_clear()
_app_ctx_stack.push(self)
appcontext_pushed.send(self.app)

追踪 _app_ctx_stack = LocalStack()中的push方法

    def push(self, obj):
"""Pushes a new item to the stack"""
rv = getattr(self._local, 'stack', None)
if rv is None:
# 执行local 对象的__setatr__方法
self._local.stack = rv = []
# 把requestContext 对象添加到列表中 self._local.stack = rv = [把requestContext]
rv.append(obj)
return rv

 

在上面的源码中有一个赋值的操作self._local.stack=rv=[],self.local=local()会触发local()对象中的__setatr__方法参数key=stack,value=[],其__setatr__方法代码如下所示

    def __setattr__(self, name, value):
# name = stack value = []
# {"唯一的表示":
# {stack:[requestContext(ctx)]}
ident = self.__ident_func__()
storage = self.__storage__
try:
storage[ident][name] = value
except KeyError:
storage[ident] = {name: value}

  

继续追踪LocalStack类中的push方法中的下rv.append(obj),把当前请求相关的数据添加到stoage中,obj是请求相关的数据RequestCotent,

{
"stack" : {"线程/协助的唯一表示":["当前请求相关的数据"]} }

g变量和 current_app

from flask import Flask,g,current_app  
其代码如下
from functools import partial
from werkzeug.local import LocalStack, LocalProxy def _lookup_req_object(name):
top = _request_ctx_stack.top
if top is None:
raise RuntimeError(_request_ctx_err_msg)
# 去requestContext中获取request的值
return getattr(top, name) def _lookup_app_object(name):
top = _app_ctx_stack.top
if top is None:
raise RuntimeError(_app_ctx_err_msg)
return getattr(top, name) def _find_app():
top = _app_ctx_stack.top
if top is None:
raise RuntimeError(_app_ctx_err_msg)
return top.app # context locals
_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()
current_app = LocalProxy(_find_app)
# partial 偏函数
request = LocalProxy(partial(_lookup_req_object, 'request'))
session = LocalProxy(partial(_lookup_req_object, 'session'))
g = LocalProxy(partial(_lookup_app_object, 'g'))

在上面的源码中,我们可以看到g是一个LocalProxy对象,其内部的参数通过偏函数partial调用_lookup_app_object函数传的参数默认为'g",_lookup_app_object代码如下

def _lookup_req_object(name):
top = _request_ctx_stack.top
if top is None:
raise RuntimeError(_request_ctx_err_msg)
# 去requestContext中获取request的值
return getattr(top, name)

top调用的是app_cxt =  LocalStack() 类中的top方法,代码如下

    def top(self):
"""The topmost item on the stack. If the stack is empty,
`None` is returned.
"""
try:
return self._local.stack[-1]
except (AttributeError, IndexError):
return None

其返回的是存储在storage{"stack":{"当前请求":[RequestContent(当前请求的数据)]}},中当前请求的数据,也就是RequestContent对象,所以上面的_llokup_req_object.函数返回的是AppContext中的g

class AppContext(object):

    def __init__(self, app):
self.app = app
self.url_adapter = app.create_url_adapter(None)
self.g = app.app_ctx_globals_class() # Like request context, app contexts can be pushed multiple times
# but there a basic "refcount" is enough to track them.
self._refcnt = 0

所以g= LocalProxy(AppContext.g) 和   current_app = LocalProxy(AppContext.app)创建一个类,其初始化的方法如下

class LocalProxy(object):

    __slots__ = ('__local', '__dict__', '__name__', '__wrapped__')

    def __init__(self, local, name=None):
# self.__loacl = local local 指的是request
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)

当我们使用g和current_app 中的方法的时候,会执行其内部的魔法方法如:

- print(g)   -->  LocalProxy对象的__str__
- g.get(')--> LocalProxy对象的__getattr__

多app应用

from werkzeug.wsgi import DispatcherMiddleware
from werkzeug.serving import run_simple
from flask import Flask, current_app app1 = Flask('app01') app2 = Flask('app02') @app1.route('/index')
def index():
return "app01" @app2.route('/index2')
def index2():
return "app2" # http://www.oldboyedu.com/index
# http://www.oldboyedu.com/sec/index2
dm = DispatcherMiddleware(app1, {
'/sec': app2,
}) if __name__ == "__main__":
app2.__call__
run_simple('localhost', 5000, dm)

with在类中的使用

class SQLHelper(object):

    def open(self):
pass def fetch(self,sql):
pass def close(self):
pass def __enter__(self):
self.open()
return self def __exit__(self, exc_type, exc_val, exc_tb):
self.close() with SQLHelper() as obj: # 自动调用类中的__enter__方法, obj就是__enter__返回值
obj.fetch('xxxx')
# 当执行完毕后,自动调用类 __exit__ 方法

flask的local中保存数据时,使用列表创建出来的栈。为什么用栈?

在写脚本的时候一个线程中执行多个app他们的关系还是嵌套的

       - 如果写web程序,web运行环境;栈中永远保存1条数据(可以不用栈)。

        - 写脚本获取app信息时,可能存在app上下文嵌套关系。

from flask import Flask,current_app,globals,_app_ctx_stack

app1 = Flask('app01')
app1.debug = False # 用户/密码/邮箱
# app_ctx = AppContext(self):
# app_ctx.app
# app_ctx.g app2 = Flask('app02')
app2.debug = True # 用户/密码/邮箱
# app_ctx = AppContext(self):
# app_ctx.app
# app_ctx.g with app1.app_context():# __enter__方法 -> push -> app_ctx添加到_app_ctx_stack.local
# {<greenlet.greenlet object at 0x00000000036E2340>: {'stack': [<flask.ctx.AppContext object at 0x00000000037CA438>]}}
print(_app_ctx_stack._local.__storage__)
print(current_app.config['DEBUG']) with app2.app_context():
# {<greenlet.greenlet object at 0x00000000036E2340>: {'stack': [<flask.ctx.AppContext object at 0x00000000037CA438> ]}}
print(_app_ctx_stack._local.__storage__)
print(current_app.config['DEBUG']) print(current_app.config['DEBUG'])

打印的数据如下

关于g变量简单的使用

我们可以在请求到来的时候,给用户赋予一些权限,在视图函数中使用

from flask import Flask,request,g

app = Flask(__name__)

@app.before_request
def before():
g.permission_code_list = ['list','add'] @app.route('/',methods=['GET',"POST"])
def index():
print(g.permission_code_list)
return "index" if __name__ == '__main__':
app.run()

Flask上下文管理源码分析 ——(3)的更多相关文章

  1. Flask上下文管理源码分析

    上下文管理本质(类似于threading.local): 1.每一个线程都会在Local类中创建一条数据: { "唯一标识":{stark:[ctx,]}, "唯一标识& ...

  2. Flask上下文管理源码--亲自解析一下

    前戏 偏函数 def index(a,b): return a+b # 原来的调用方法 # ret=index(1,2) # print(ret) # 偏函数--帮助开发者自动传递参数 import ...

  3. Flask系列之源码分析(一)

    目录: 涉及知识点 Flask框架原理 简单示例 路由系统原理源码分析 请求流程简单源码分析 响应流程简单源码分析 session简单源码分析 涉及知识点 1.装饰器 闭包思想 def wapper( ...

  4. java 1.8 动态代理源码分析

    JDK8动态代理源码分析 动态代理的基本使用就不详细介绍了: 例子: class proxyed implements pro{ @Override public void text() { Syst ...

  5. Spring Boot自动装配原理源码分析

    1.环境准备 使用IDEA Spring Initializr快速创建一个Spring Boot项目 添加一个Controller类 @RestController public class Hell ...

  6. Flask Session 使用和源码分析 —— (6)

    基本使用 from flask import Flask, session, redirect, url_for, escape, request app = Flask(__name__) @app ...

  7. flask/app.py-add_url_rule源码分析

    之前分析route方法的时候,可以看到中间会调用add_url_rule方法,add_url_rule方法和route方法一样属于Flask这个类的. add_url_rule方法主要用来连接url规 ...

  8. JDK7动态代理源码分析

    IObject proxy = (IObject) Proxy.newProxyInstance(IObject.class.getClassLoader(), new Class[]{IObject ...

  9. (转)Spring对注解(Annotation)处理源码分析1——扫描和读取Bean定义

    1.从Spring2.0以后的版本中,Spring也引入了基于注解(Annotation)方式的配置,注解(Annotation)是JDK1.5中引入的一个新特性,用于简化Bean的配置,某些场合可以 ...

随机推荐

  1. DSAPI多功能组件编程应用-网络相关(下)

    [DSAPI.DLL下载地址] 在本篇,我将重点介绍DSAPI.DLL中Socket编程的使用.众所周知,Socket用起来不难,但是写起来麻烦.我对Socket进行了封装,进行了高度简化.下面我将通 ...

  2. vue axios 批量删除 数组参数

    方法一:前端循环请求服务器端delete(id)方法 请问如何获得element-ui表格中的勾选项index,以实现批量删除功能 https://segmentfault.com/q/1010000 ...

  3. 学JAVA的第二天,静态网站制作,脑阔一点疼

    先从下载apache-tomcat-9.0.17开始 在下边这个网站下载,下边一步步来 下面删除的这些是暂时用不上的,先吧它删除了,因为会拖慢启动速度 下边把ROOT里边除WEB-INF外的全不删除了 ...

  4. Java开发笔记(四十五)成员属性与成员方法

    前面介绍了许多数据类型,除了基本类型如整型int.双精度型double.布尔型boolean之外,还有高级一些的如包装整型Integer.字符串类型String.本地日期类型LocalDate等等,那 ...

  5. Django验证码【附源码】

    一.安装依赖 CentOS 第一步: yum install python-devel 第二步: yum install freetype-devel libjpeg-devel libpng-dev ...

  6. ListView刷新某一项Item

    ListView现在已经很少被使用,但还是在这里列出来说一下,有时候我们仅仅需要改变listView的某个Item,如果调用adapter的notifyDataSetChanged()方法效率不高,并 ...

  7. ionic3 Alert组件的使用方法

    html页面 <button ion-button color="danger" class="button-block button-round-ios" ...

  8. linux(centos7) 常用命令和快捷键 持续验证更新中...

    1.文件和目录cd 进入目录示例:cd /home 进入home目录    cd..    返回上一级目录cd../..    返回上两级目录cd -    返回上次所在目录cd ~    返回根目录 ...

  9. 前后端分离djangorestframework—— 接入支付宝支付平台

    支付宝 简介 支付宝是什么不用多说了,本次教程适合初学者 前提准备 话不多说,干就完了 1.注册开发者账号,设置公钥私钥 首先进入支付宝开发者平台:传送门 ,有账号直接登录,没账号用你平时用来付款收钱 ...

  10. some settings for spacemacs golang

    spacemacs 中的 golang配置 spacemacs 中的 golang layer 已经有很多默认的配置了, 但是都是针对在 GOPATH 下的配置. 如果你的项目不再默认 的 GOPAT ...