一、裝飾器html
閉包思想python
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__)
二、面向對象封裝json
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('18','石鵬') b1 = Bar(1) print(b1.obj.name)
三、python對象什麼後面能夠加括號flask
- 函數
- 類
- 方法
- 對象
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)
四、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')
五、函數和方法的區別cookie
在於調用時有沒有實例化對象,即跟某個對象關聯。session
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
一、框架本質爲經過socket模塊實現工做流的請求和響應。閉包
經過socket創建實例,accept等待請求地址,並經過編寫路由系統來給予相應的響應。app
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()
二、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)
三、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()
一、實現簡單登錄
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 == '123': 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()
<!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>
<!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>
二、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
ps.import importlib模塊,模塊支持傳遞字符串來導入模塊。咱們先來建立一些簡單模塊一遍演示。咱們在模塊裏提供了相同接口,經過打印它們自身名字來區分。可經過importlib.import_module(module_path)來動態導入。其等價於import module_path。
一、整體流程:
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()
二、初始化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)
三、調用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
四、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)
五、 add_url_rule方法rule = self.url_rule_class調用Rule方法,封裝url和試圖函數
add_url_rule,代碼同4 ;經過url_rule_class = Rule實例化,代碼同2
六、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.已生成路由後,由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方法
二、__call__方法會觸發wsgi_app
def __call__(self, environ, start_response): """Shortcut for :attr:`wsgi_app`.""" return self.wsgi_app(environ, start_response)
三、ctx=request_context對象,觸發request_context對象
def wsgi_app(self, environ, start_response): ctx = self.request_context(environ) ctx.push()
四、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()
五、flask初始化經過request實例化調用Request對象,經過request實例化調用Request對象
class Flask(_PackageBoundObject):
request_class = Request
六、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
七、.存儲到ctx中
同3代碼
八、ctx.push()調用RequestContest.push方法
同3代碼
一、綜述
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
二、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 # 九、結束 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)
三、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()
四、經過session_interface變量調用到secureCookieSeeionInerface類的open_session
class Flask(_PackageBoundObject): session_interface = SecureCookieSessionInterface()
五、若是沒有,則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類
六、將加密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()
七、執行視圖函數
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)
八、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
九、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
十、經過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)
十一、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)