Flask系列之源码分析(一)
目录:
- 涉及知识点
- Flask框架原理
- 简单示例
- 路由系统原理源码分析
- 请求流程简单源码分析
- 响应流程简单源码分析
- session简单源码分析
涉及知识点
1、装饰器
闭包思想
def wapper(func):
def inner(*args,**kwargs):
return func(*args,**kwargs)
return inner """
1. 立即执行wapper函数,并将下面装饰的函数当做参数传递
2. 将wapper函数返回值获取,在index赋值
index = inner函数
"""
@wapper
def index():
print('函数内容') # 实际执行的 inner函数,inner函数内部调用原函数
index()
ps.@functools.wraps,以上我们知道了python实现闭包,实际是index = inner(index)的封装思想。但不可避免的是inner封装后,会对封装的函数隐藏一些信息。如:包装异常,隐藏异常,打印日志,统计函数使用时间等。@functools.wraps通过update_wrapper函数,用参数wrapped表示的函数对象(例如:square)的一些属性(如:__name__、 __doc__)覆盖参数wrapper表示的函数对象(例如:callf,这里callf只是简单地调用square函数,因此可以说callf是 square的一个wrapper function)的这些相应属性。
import functools
def wapper(func):
@functools.wraps(func)
def inner(*args,**kwargs):
return func(*args,**kwargs)
return inner @wapper
def index():
print('函数内容') @wapper
def order():
print('函数内容') print(index.__name__)
print(order.__name__)
2、面向对象封装
class Foo(object):
def __init__(self,age,name):
self.age = age
self.name = name class Bar(object):
def __init__(self,counter):
self.counter = counter
self.obj = Foo('','石鹏') b1 = Bar(1)
print(b1.obj.name)
3、python对象什么后面可以加括号
- 函数
- 类
- 方法
- 对象
def f1():
print('f1') class F2(object):
pass class F3(object):
def __init__(self):
pass def ff3(self):
print('ff3') class F4(object):
def __init__(self):
pass def __call__(self, *args, **kwargs):
print('f4') def func(arg):
"""
由于arg在函数中加括号,所以他只有4中表现形式:
- 函数
- 类
- 方法
- 对象
:param arg:
:return:
"""
arg() # 1. 函数,内部执行函数
func(f1)
# 2. 类,内部执行__init__方法
func(F2) # 3. 方法,obj.ff3
obj1 = F3()
func(obj1.ff3) # 4. 对象
obj2 = F4()
func(obj2)
4、call方法
class F4(object):
def __init__(self):
print('构造方法') def __call__(self, *args, **kwargs):
print('f4') def run(self,str1):
print("run:%s" % str1) obj = F4()
obj()
obj.run('sssss')
5、函数和方法的区别
在于调用时有没有实例化对象,即跟某个对象关联。
from types import MethodType,FunctionType class F3(object):
def __init__(self):
pass def ff3(self):
print('ff3') #
v1 = isinstance(F3.ff3,MethodType) # 方法
v2 = isinstance(F3.ff3,FunctionType) # 函数
print(v1,v2) # False,True obj = F3()
v1 = isinstance(obj.ff3,MethodType) # 方法
v2 = isinstance(obj.ff3,FunctionType) # 函数
print(v1,v2) # True False
Flask框架原理
1、框架本质为通过socket模块实现工作流的请求和响应。
通过socket建立实例,accept等待请求地址,并通过编写路由系统来给予相应的响应。
import socket def main():
# 创建老师
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('localhost', 8000))
sock.listen(5) while True:
# 老师等待 用户请求的到来
connection, address = sock.accept() # 获取发送的内容:吴亦凡有没有女朋友?
buf = connection.recv(1024) # 根据请求URL的不同:
# 回答:没有
connection.send(b"HTTP/1.1 200 OK\r\n\r\n")
connection.send(b"No No No") # 关闭连接
connection.close() if __name__ == '__main__':
main()
2、flask通过werkzeug模块来帮助我们完成socket性能。
"""
from werkzeug.wrappers import Request, Response
from werkzeug.serving import run_simple @Request.application
def hello(request):
return Response('Hello World!') if __name__ == '__main__':
# 当请求打来之后,自动执行:hello()
run_simple('localhost', 4000, hello)
""" from werkzeug.wrappers import Request, Response
from werkzeug.serving import run_simple class Foo(object):
def __call__(self, *args, **kwargs):
return Response('Hello World!') if __name__ == '__main__':
# 当请求打来之后,自动执行:hello()
obj = Foo()
run_simple('localhost', 4000, obj)
3、flask快速入门
"""
pip install flask
pip3 install flask
""" from flask import Flask
# 1. 实例化Flask对象
app = Flask('xxxx') """
1. 执行 app.route('/index')并获取返回值 xx
2.
@xx
def index():
return 'Hello World'
3. 执行 index = xx(index)
本质:
{
'/index': index
}
"""
@app.route('/index')
def index():
return 'Hello World' if __name__ == '__main__':
app.run()
简单示例
1、实现简单登陆
import functools
from flask import Flask,render_template,request,redirect,session app = Flask('xxxx',template_folder="templates")
app.secret_key = 'as923lrjks9d8fwlkxlduf' def auth(func):
@functools.wraps(func)
def inner(*args,**kwargs):
user_info = session.get('user_info')
if not user_info:
return redirect('/login')
return func(*args,**kwargs)
return inner """
{
/order: inner函数, name: order
/index: inner函数, name: index
}
""" @app.route('/order',methods=['GET'])
@auth
def order():
user_info = session.get('user_info')
if not user_info:
return redirect('/login') return render_template('index.html') @app.route('/index',methods=['GET'])
@auth
def index():
return render_template('index.html') @app.route('/login',methods=['GET','POST'])
def login():
if request.method == "GET":
return render_template('login.html')
else:
user = request.form.get('user')
pwd = request.form.get('pwd')
if user == 'alex' and pwd == '':
session['user_info'] = user
return redirect('/index')
# return render_template('login.html',msg = "用户名或密码错误",x = 123)
return render_template('login.html',**{'msg':'用户名或密码错误'}) @app.route('/logout',methods=['GET'])
def logout():
del session['user_info']
return redirect('/login') if __name__ == '__main__':
app.run()
app.py
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>登录页面</h1>
<form method="post">
<input type="text" name="user">
<input type="password" name="pwd">
<input type="submit" value="提交">{{msg}}
</form>
</body>
</html>
templates/login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>欢迎进入系统</h1>
<img src="/static/111.png" alt="">
</body>
</html>
templates/index.html
2、flask配置文件
import functools
from flask import Flask # 配置:模板/静态文件
app = Flask('xxxx',template_folder="templates")
# 配置:secret_key
app.secret_key = 'as923lrjks9d8fwlkxlduf' # 导入配置文件
app.config.from_object('settings.TestingConfig') @app.route('/index')
def index():
return "index" if __name__ == '__main__':
app.run()
class BaseConfig(object):
DEBUG = False
SESSION_REFRESH_EACH_REQUEST = True class ProConfig(BaseConfig):
pass class DevConfig(BaseConfig):
DEBUG = True class TestingConfig(BaseConfig):
DEBUG = True
settings.py
ps.import importlib模块,模块支持传递字符串来导入模块。我们先来创建一些简单模块一遍演示。我们在模块里提供了相同接口,通过打印它们自身名字来区分。可通过importlib.import_module(module_path)来动态导入。其等价于import module_path。
路由系统原理源码分析
1、总体流程:
1.初始化Flask类,Rule类,Map类
2.调用app.route方法
3.route方法调用add_url_rule方法
4. add_url_rule方法rule = self.url_rule_class调用Rule方法,封装url和试图函数
5.add_url_rule方法调用url_map.add(Rule)对路由的rules进行添加[Rule('/index', 函数),]
6.map类存到self.url_map中,Rule存在url_rule_class中
import functools
from flask import Flask,views # 配置:模板/静态文件
app = Flask('xxxx',template_folder="templates")
"""
{
'/index': index函数
} 1. decorator = app.route('/index')
2.
@decorator
def index():
return "index"
3. decorator(index)
""" """
Map() = [
Rule(rule=/index/ endpoint=None view_func=函数),
]
"""
@app.route('/index')
def index():
return "index" """
Map() = [
Rule(rule=/index endpoint=None view_func=函数),
Rule(rule=/order endpoint=None view_func=order),
]
"""
def order():
return 'Order'
app.add_url_rule('/order', None, order) class TestView(views.View):
methods = ['GET']
def dispatch_request(self):
return 'test!' app.add_url_rule('/test', view_func=TestView.as_view(name='test')) # name=endpoint
# app.add_url_rule('/test', view_func=view函数) # name=endpoint def auth(func):
def inner(*args, **kwargs):
print('before')
result = func(*args, **kwargs)
print('after')
return result
return inner class X1View(views.MethodView):
methods = ['GET','POST']
decorators = [auth, ] def get(self):
return 'x1.GET' def post(self):
return 'x1.POST' app.add_url_rule('/x1', view_func=X1View.as_view(name='x1')) # name=endpoint if __name__ == '__main__':
app.run()
2、初始化Flask类,Rule类,Map类
#--------------------------------------
# Flask类
class Flask(_PackageBoundObject):
url_rule_class = Rule
def __init__(self, import_name, static_path=None, static_url_path=None,
static_folder='static', template_folder='templates',
instance_path=None, instance_relative_config=False,
root_path=None)
self.url_map = Map() #--------------------------------------
# Role类
@implements_to_string
class Rule(RuleFactory):
def __init__(self, string, defaults=None, subdomain=None, methods=None,
build_only=False, endpoint=None, strict_slashes=None,
redirect_to=None, alias=False, host=None):
if not string.startswith('/'):
raise ValueError('urls must start with a leading slash')
self.rule = string
self.is_leaf = not string.endswith('/') self.map = None
self.strict_slashes = strict_slashes
self.subdomain = subdomain
self.host = host
self.defaults = defaults
self.build_only = build_only
self.alias = alias
if methods is None:
self.methods = None
else:
if isinstance(methods, str):
raise TypeError('param `methods` should be `Iterable[str]`, not `str`')
self.methods = set([x.upper() for x in methods])
if 'HEAD' not in self.methods and 'GET' in self.methods:
self.methods.add('HEAD')
self.endpoint = endpoint
self.redirect_to = redirect_to if defaults:
self.arguments = set(map(str, defaults))
else:
self.arguments = set()
self._trace = self._converters = self._regex = self._weights = None #-------------------
#map类
class Map(object):
default_converters = ImmutableDict(DEFAULT_CONVERTERS) def __init__(self, rules=None, default_subdomain='', charset='utf-8',
strict_slashes=True, redirect_defaults=True,
converters=None, sort_parameters=False, sort_key=None,
encoding_errors='replace', host_matching=False):
self._rules = []
self._rules_by_endpoint = {}
self._remap = True
self._remap_lock = Lock() self.default_subdomain = default_subdomain
self.charset = charset
self.encoding_errors = encoding_errors
self.strict_slashes = strict_slashes
self.redirect_defaults = redirect_defaults
self.host_matching = host_matching self.converters = self.default_converters.copy()
if converters:
self.converters.update(converters) self.sort_parameters = sort_parameters
self.sort_key = sort_key for rulefactory in rules or ():
self.add(rulefactory)
3、调用app.route方法
def route(self, rule, **options):
def decorator(f):
endpoint = options.pop('endpoint', None)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
4、route方法调用add_url_rule方法
@setupmethod
def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
if endpoint is None:
endpoint = _endpoint_from_view_func(view_func)
options['endpoint'] = endpoint
methods = options.pop('methods', None) # if the methods are not given and the view_func object knows its
# methods we can use that instead. If neither exists, we go with
# a tuple of only ``GET`` as default.
if methods is None:
methods = getattr(view_func, 'methods', None) or ('GET',)
if isinstance(methods, string_types):
raise TypeError('Allowed methods have to be iterables of strings, '
'for example: @app.route(..., methods=["POST"])')
methods = set(item.upper() for item in methods) # Methods that should always be added
required_methods = set(getattr(view_func, 'required_methods', ())) # starting with Flask 0.8 the view_func object can disable and
# force-enable the automatic options handling.
provide_automatic_options = getattr(view_func,
'provide_automatic_options', None) if provide_automatic_options is None:
if 'OPTIONS' not in methods:
provide_automatic_options = True
required_methods.add('OPTIONS')
else:
provide_automatic_options = False # Add the required methods now.
methods |= required_methods rule = self.url_rule_class(rule, methods=methods, **options)
rule.provide_automatic_options = provide_automatic_options self.url_map.add(rule)
5、 add_url_rule方法rule = self.url_rule_class调用Rule方法,封装url和试图函数
add_url_rule,代码同4 ;通过url_rule_class = Rule实例化,代码同2
6、add_url_rule方法调用url_map.add(Rule)对路由的rules进行添加[Rule('/index', 函数),]
add_url_rule代码同4,调用url_map.add方法
def add(self, rulefactory):
"""Add a new rule or factory to the map and bind it. Requires that the
rule is not bound to another map. :param rulefactory: a :class:`Rule` or :class:`RuleFactory`
"""
for rule in rulefactory.get_rules(self):
rule.bind(self)
self._rules.append(rule)
self._rules_by_endpoint.setdefault(rule.endpoint, []).append(rule)
self._remap = True
7.map类存到self.url_map中,Rule存在url_rule_class中。
同代码2.
请求流程简单源码分析
1、综述:
1.已生成路由后,由app.run执行run方法
2.run方法通过werkzeug模块执行run_simple方法
3.werkzeug模块会触发__call__方法
4.__call__方法会触发wsgi_app
5.ctx=request_context对象,触发request_context对象
6.request_context对象__init__进行实例化
--request = app.request_class(environ)
7.flask初始化通过request实例化调用Request对象,通过request实例化调用Request对象
8.Request对象通过werkzeug模块__init__进行实例化
9.存储到ctx中
10.ctx.push()调用RequestContest.push方法
2、__call__方法会触发wsgi_app
def __call__(self, environ, start_response):
"""Shortcut for :attr:`wsgi_app`."""
return self.wsgi_app(environ, start_response)
3、ctx=request_context对象,触发request_context对象
def wsgi_app(self, environ, start_response):
ctx = self.request_context(environ)
ctx.push()
4、request_context对象__init__进行实例化
def request_context(self, environ):
return RequestContext(self, environ)
--request = app.request_class(environ)
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 contexts can be pushed multiple times and interleaved with
# other request contexts. Now only if the last level is popped we
# get rid of them. Additionally if an application context is missing
# one is created implicitly so for each level we add this information
self._implicit_app_ctx_stack = [] # indicator if the context was preserved. Next time another context
# is pushed the preserved context is popped.
self.preserved = False # remembers the exception for pop if there is one in case the context
# preservation kicks in.
self._preserved_exc = None # Functions that should be executed after the request on the response
# object. These will be called before the regular "after_request"
# functions.
self._after_request_functions = [] self.match_request()
5、flask初始化通过request实例化调用Request对象,通过request实例化调用Request对象
class Flask(_PackageBoundObject):
request_class = Request
6、Request对象通过werkzeug模块__init__进行实例化
class Request(RequestBase):
#: The internal URL rule that matched the request. This can be
#: useful to inspect which methods are allowed for the URL from
#: a before/after handler (``request.url_rule.methods``) etc.
#:
#: .. versionadded:: 0.6
url_rule = None #: A dict of view arguments that matched the request. If an exception
#: happened when matching, this will be ``None``.
view_args = None #: If matching the URL failed, this is the exception that will be
#: raised / was raised as part of the request handling. This is
#: usually a :exc:`~werkzeug.exceptions.NotFound` exception or
#: something similar.
routing_exception = None # Switched by the request context until 1.0 to opt in deprecated
# module functionality.
_is_old_module = False
7、.存储到ctx中
同3代码
8、ctx.push()调用RequestContest.push方法
同3代码
flask的sesstion流程
1、综述
1.RequestContext.push,调用app.open_sesstion
2.self.session调用app.open_session
3.通过session_interface变量调用到secureCookieSeeionInerface类的open_session
4.如果没有,则session_class = SecureCookieSession,open_session经过loads加密返回self.session_class(),
5.将加密session返回到self.session
6.执行视图函数
response = self.full_dispatch_request()
----调用try_trigger_before_first_request_functions
(before_first_request)
----调用preprocess_request(before_request)
----调用dispatch_request(执行试图函数)
----调用finalize_request(@fater_request)
7.finalize_request
----response = self.process_response(response)
8.process_response
----执行@fater_request函数
----self.save_session(ctx.session, response)
9.通过self.save_session调用save_session并返回SecureCookieSessionInterface.save_session(self, session, response)
10.save_session保存session,报错return null
2、RequestContext.push,调用app.open_sesstion
def wsgi_app(self, environ, start_response):
ctx = self.request_context(environ)
ctx.push()
error = None
try:
try:
# 4 执行视图函数
response = self.full_dispatch_request()
except Exception as e:
# 异常处理试图报错,包含信号2345报错执行,got_request_exception信号
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 # 9、结束
ctx.auto_pop(error)
通过self.session = self.app.open_session(self.request)调用flask.open_session方法
def open_session(self, request):
return self.session_interface.open_session(self, request)
3、self.session调用app.open_session
class RequestContext(object):
def push(self):
self.session = self.app.open_session(self.request)
if self.session is None:
self.session = self.app.make_null_session()
4、通过session_interface变量调用到secureCookieSeeionInerface类的open_session
class Flask(_PackageBoundObject):
session_interface = SecureCookieSessionInterface()
5、如果没有,则session_class = SecureCookieSession,open_session经过loads加密返回self.session_class(),
class SecureCookieSessionInterface(SessionInterface):
"""The default session interface that stores sessions in signed cookies
through the :mod:`itsdangerous` module.
"""
#: the salt that should be applied on top of the secret key for the
#: signing of cookie based sessions.
salt = 'cookie-session'
#: the hash function to use for the signature. The default is sha1
digest_method = staticmethod(hashlib.sha1)
#: the name of the itsdangerous supported key derivation. The default
#: is hmac.
key_derivation = 'hmac'
#: A python serializer for the payload. The default is a compact
#: JSON derived serializer with support for some extra Python types
#: such as datetime objects or tuples.
serializer = session_json_serializer
session_class = SecureCookieSession
def open_session(self, app, request):
# sission,key值
s = self.get_signing_serializer(app)
if s is None:
return None
# 如果能从cookie拿到session的话
val = request.cookies.get(app.session_cookie_name)
if not val:
return self.session_class() #如果没有session,则返回一个空字典
max_age = total_seconds(app.permanent_session_lifetime)
try:
data = s.loads(val, max_age=max_age) # 加密保存
return self.session_class(data)
except BadSignature:
return self.session_class() # 返回session类
6、将加密session返回到self.session
class RequestContext(object):
def push(self):
self.session = self.app.open_session(self.request)
if self.session is None:
self.session = self.app.make_null_session()
7、执行视图函数
response = self.full_dispatch_request()
同代码2
----调用try_trigger_before_first_request_functions
(before_first_request)
def full_dispatch_request(self):
"""Dispatches the request and on top of that performs request
pre and postprocessing as well as HTTP exception catching and
error handling. .. versionadded:: 0.7
"""
# 触发只执行一次的装饰器函数,@before_first_request
self.try_trigger_before_first_request_functions()
----调用preprocess_request(before_request)
----调用dispatch_request(执行试图函数)
----调用finalize_request(@fater_request)
def full_dispatch_request(self):
try:
# 执行特殊装饰器:before_request装饰的所有函数
# 如果没有返回值,rv=None;有返回值 “嘻嘻嘻”
rv = self.preprocess_request()
if rv is None:
# 触发执行视图函数,使用session
rv = self.dispatch_request()
except Exception as e:
rv = self.handle_user_exception(e)
# 6 对返回值进行封装,执行@fater_request装饰器;session保存
return self.finalize_request(rv)
8、finalize_request
----response = self.process_response(response)
def finalize_request(self, rv, from_error_handler=False):
''' 创建返视图返回'''
response = self.make_response(rv)
try:
'''返回值'''
response = self.process_response(response)
# 执行信号request_finished
request_finished.send(self, response=response)
except Exception:
if not from_error_handler:
raise
self.logger.exception('Request finalizing failed with an '
'error while handling an error')
return response
9、process_response
----执行@fater_request函数
----self.save_session(ctx.session, response)
def process_response(self, response):
ctx = _request_ctx_stack.top
bp = ctx.request.blueprint
funcs = ctx._after_request_functions
if bp is not None and bp in self.after_request_funcs:
funcs = chain(funcs, reversed(self.after_request_funcs[bp]))
if None in self.after_request_funcs:
funcs = chain(funcs, reversed(self.after_request_funcs[None]))
# 执行 after_request装饰器
for handler in funcs:
response = handler(response)
# 将内存中的session持久化到:数据库、....
if not self.session_interface.is_null_session(ctx.session):
self.save_session(ctx.session, response)
return response
10、通过self.save_session调用save_session并返回SecureCookieSessionInterface.save_session(self, session, response)
# Flask类
def save_session(self, session, response):
return self.session_interface.save_session(self, session, response)
11、save_session保存session,报错return null
SecureCookieSessionInterface类:
def save_session(self, app, session, response):
domain = self.get_cookie_domain(app) # 域名
path = self.get_cookie_path(app) # 路径 # Delete case. If there is no session we bail early.
# If the session was modified to be empty we remove the
# whole cookie.
if not session:
if session.modified:
response.delete_cookie(app.session_cookie_name,
domain=domain, path=path)
return # Modification case. There are upsides and downsides to
# emitting a set-cookie header each request. The behavior
# is controlled by the :meth:`should_set_cookie` method
# which performs a quick check to figure out if the cookie
# should be set or not. This is controlled by the
# SESSION_REFRESH_EACH_REQUEST config flag as well as
# the permanent flag on the session itself.
if not self.should_set_cookie(app, session):
return httponly = self.get_cookie_httponly(app)
secure = self.get_cookie_secure(app)
expires = self.get_expiration_time(app, session)
val = self.get_signing_serializer(app).dumps(dict(session)) # 加密
response.set_cookie(app.session_cookie_name, val, # 最后保存在cookie中
expires=expires, httponly=httponly,
domain=domain, path=path, secure=secure)
附录
Flask系列之源码分析(一)的更多相关文章
- Flask系列之源码分析(二)
应用技术点 python之__setattr__ python之threading.local python之偏函数 flask源码上下文管理 1.综述过程 将请求对象压入栈 1.请求进入 __cal ...
- Spring基础系列-AOP源码分析
原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9560803.html 一.概述 Spring的两大特性:IOC和AOP. AOP是面向切 ...
- flask/app.py-add_url_rule源码分析
之前分析route方法的时候,可以看到中间会调用add_url_rule方法,add_url_rule方法和route方法一样属于Flask这个类的. add_url_rule方法主要用来连接url规 ...
- Tomcat详解系列(3) - 源码分析准备和分析入口
Tomcat - 源码分析准备和分析入口 上文我们介绍了Tomcat的架构设计,接下来我们便可以下载源码以及寻找源码入口了.@pdai 源代码下载和编译 首先是去官网下载Tomcat的源代码和二进制安 ...
- Flask之wtforms源码分析
一.wtforms源码流程 1.实例化流程分析 # 源码流程 1. 执行type的 __call__ 方法,读取字段到静态字段 cls._unbound_fields 中: meta类读取到cls._ ...
- Kafka源码系列之源码分析zookeeper在kafka的作用
浪尖的kafka源码系列以kafka0.8.2.2源码为例给大家进行讲解的.纯属个人爱好,希望大家对不足之处批评指正. 一,zookeeper在分布式集群的作用 1,数据发布与订阅(配置中心) 发布与 ...
- Android进阶系列之源码分析Activity的启动流程
美女镇楼,辟邪! 源码,是一个程序猿前进路上一个大的而又不得不去翻越障碍,我讨厌源码,看着一大堆.5000多行,要看完得啥时候去了啊.不过做安卓的总有这一天,自从踏上这条不归路,我就认命了.好吧,我慢 ...
- flask请求上下文源码分析
一.什么是上下文 每一段程序都有很多外部变量,只有像add这种简单的函数才是没有外部变量的,一旦你的一段程序有了外部变量,这段程序就不完整了,不能独立运行,你为了使他们能运行,就要给所有的外部变量一个 ...
- Spring IOC 容器源码分析系列文章导读
1. 简介 Spring 是一个轻量级的企业级应用开发框架,于 2004 年由 Rod Johnson 发布了 1.0 版本.经过十几年的迭代,现在的 Spring 框架已经非常成熟了.Spring ...
随机推荐
- UGUI 的多分辨率适配
1.Canvas的属性配置 2.Canvas Scaler的属性配置 3.根据不同的屏幕的比例动态修改缩放基准 void Start () { float standard_width = 960f; ...
- HDOJ 4276 The Ghost Blows Light
题意 1. 给定一棵树, 树上节点有 value, 节点之间 travel 有 cost. 给定起始节点和最大 cost, 求解最大 value 思路 1. 寻找最短路径 a. 题目描述中有两句话, ...
- Android开发之--常用颜色值
<?xml version="1.0" encoding="utf-8" ?> <resources> <color name=& ...
- linux复制文件到指定的文件夹
copy命令 该命令的功能是将给出的文件或目录拷贝到另一文件或目录中,同MSDOS下的copy命令一样,功能十分强大. 语法: cp [选项] 源文件或目录 目标文件或目录 说明:该命令把指 ...
- iOS开发:iOS中图片与视频一次性多选 - v2m
一.使用系统的Assets Library Framework这个是用来访问Photos程序中的图片和视频的库.其中几个类解释如下 ALAsset ->包含一个图片或视频的各种信息 ALAsse ...
- PHP之命名空间
前面的话 从广义上来说,命名空间是一种封装事物的方法.在很多地方都可以见到这种抽象概念.例如,在操作系统中目录用来将相关文件分组,对于目录中的文件来说,它就扮演了命名空间的角色.这个原理应用到程序设计 ...
- JavaWeb温习之防止表单重复提交
表单重复提交主要有以下三种情况: 1. 在网络延迟的情况下让用户有时间点击多次submit按钮导致表单重复提交 2. 表单提交后用户点击[刷新]按钮导致表单重复提交 3. 用户提交表单后,点击浏览器的 ...
- hdu 5318 The Goddess Of The Moon
The Goddess Of The Moon Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/ ...
- Array.prototype.forEach数组遍历
forEach是Array新方法中最基本的一个,就是遍历,循环.先看以前是怎么遍历数组的 常用遍历 var arr = [1,2,3,4,5]; for(var i = 0; i < arr.l ...
- node中的对象
1. class的概念 定义一个class,属性都是private,方法都是public. Hello.js: 使用class index.js: 2. 单例类 使用exports而不是module. ...