題目部分參考:http://www.javashuo.com/article/p-pnkalxbn-d.htmlcss
縮進:4個空格
空行:函數與函數之間空兩行,類內部的函數之間空一行
命名:
一、函數名小寫,可採用下劃線加字母;類名單詞第一個字母大寫,採用駝峯式命名;
二、命名必須有意義,可識別性,不能重複;
長度:每行長度不能超過79,能夠採用下劃線隔開並另起一行
空格:逗號以後和操做符先後採用空格隔開;
import:不要一次導入多個不是一個類型的庫;
常量採用大寫html
bin:十進制轉二進制,例如 bin(10)=0b1010
oct:十進制轉八進制, octonary number system(八進制)
hex:十進制轉十六進制,hexadecimal
int:將對應的進制轉換成十進制前端
手動轉換參考:https://jingyan.baidu.com/article/495ba84109665338b30ede98.htmlpython
def convert_to_int(ip): lst = [int(item) for item in ip.split('.') if item] return sum(lst)
def foo(n): print(n) n += 1 foo(n) if __name__ == '__main__': foo(1)
x or y:若x爲真,則爲x,不然爲y;
x and y:若x爲真,則爲y,反之爲x。
x and y or z:等價於 x and (y or z)mysql
# 運算符優先級:比較運算符< 高於 等於運算符== 1 < (2==2) # False,等價與1<1 1 < 2 == 2 # True,等價與 1<2 and 2
二進制下運算符號,能夠理解爲與、或、非。
&:按位與,都爲1則爲1,例如 print(10&8)=0b1010 & 0b1000 = 0b1000 = 8
。
|:按位或,有一個爲真則爲真。
:當兩個對應的二進制相異時,則結果爲1,例如print(10^8)=0b0010=2
linux
它們都是編碼類型,都包含二進制與字符的對應關係。
ascii:僅僅包含 阿拉伯字母以及某些運算符與二進制的對應關係,最先的編碼類型,但最多隻能表示一個字節,即256個。
unicode:全球通用的編碼,包含全部字符與二進制的對應關係,任何字符==2Bytes
,因此用來存儲英文字符浪費空間。
gbk:本國語言與二進制的對應關係,每一個國家都有本身的GBK編碼,沒有統一塊兒來,其中一箇中文字符==2Bytes,一個英文字符==1Bytes
。
utf8:unicode的升級版本,一箇中文字符==3Bytes,英文字符==1Bytes,歐洲字符==2Bytes
。git
機器碼:Native code,原生碼,cpu能夠直接解讀的數據,執行速度最快;
字節碼:Byte-code中間狀態的二進制代碼(文件),須要直譯器轉譯才難成爲機器碼。程序員
is比較的是內存地址,能夠用id()查看;
==比較的是 值是否相等。web
可變數據類型:變量的值發生改變(指的是對它進行增改操做,而非從新賦值),那麼它對應的內存地址不會發生改變。例如:list、dict、set。面試
In [32]: l=[1,2] In [33]: id(l) Out[33]: 4495524232 In [34]: l.append(3) In [35]: id(l) Out[35]: 4495524232
不可變數據類型:變量的值發生改變,那麼它對應的內存地址會發生改變,例如:str,int,float,tuple。
In [28]: a=1 In [29]: id(a) Out[29]: 4462312528 In [30]: a=2 In [31]: id(a) Out[31]: 4462312560
變量本質上是對內存地址的引用。
題目:
v = dict.fromkeys(['k1', 'k2'], []) # 該字典val是列表,且都指向此列表 v['k1'].append(666) print(v) v['k1'] = 777 print(v) # 結果: {'k1': [666], 'k2': [666]} {'k1': 777, 'k2': [666]} v1 = dict.fromkeys(['k1', 'k2']) print(v1) # {'k1': None, 'k2': None} v2 = dict.fromkeys(['k1', 'k2'], []) print(v2) # {'k1': [], 'k2': []}
int和str都存在一個小數據池,在這個範圍內,若變量值相同,都會指向同一個內存地址,超過這個池子的範圍,會另外開闢新的內存空間。
int小數據池:int在【-5,256】範圍內,建立相同的數字會指向同一個內存地址,超過了這個範圍,就會指向不一樣的地址。
字符串小數據池範圍:
一、不能有空格:如有空格,則指向兩個內存地址;
二、不能包含特殊字符,若包含特殊字符,則指向兩個內存地址。
結構:結果1 + if + 條件 + else + 結果2,若條件爲True,則返回結果1,反之返回結果2。
print格式不一樣。
range()不一樣:在py2中是range是列表,xrange纔是生成器,在py3只有range且是生成器。
默認編碼不一樣:py2的默認編碼是ascii,py3的默認編碼是utf8。
a,b=b,a
能夠經過三元表達式判斷,例如:'true' if 1 else 'else'
數字類型:0爲False,其他的爲True
None爲False
列表、tupe、字典、set等數據類型長度爲0爲false
str類型爲不可變類型,沒有增刪改查方法,經常使用方法以下:
統計: count(s):統計s出現的次數 查詢: index(s):在指定的索引範圍內從左到右找出元素s的索引並返回; find(s,begin,end):同index方法; 格式輸出: lower():將字母改成小寫格式; upper():將字母改成大寫格式; capitalize():將首個字母改成大寫; strip():刪除字符串兩側的空格並返回,可是不改變原字符串; format(): In [32]: '{}-{}-{}'.format('alex','kate','bo') Out[32]: 'alex-kate-bo' In [33]: '{1}-{0}-{2}'.format('alex','kate','bo') Out[33]: 'kate-alex-bo' swapcase(): 大小寫反轉。 類型轉換: s.split(sep):轉換成列表 替換: s.replace(old,new) 判斷is系列: isdigits() isalpha() isnumeric() islowe() isupper() 判斷開頭和結尾: startwith(s) endwith(s)
list類型爲可變數據類型,能夠進行增刪改查,經常使用方法以下:
建立列表:list('iterable') 增長: append(s):在列表右側追加元素; extend(iterable):循環可迭代對象並添加到列表中, 例如:[1].extend('abcd')=[1,'a','b','c','d']; 刪除: pop(index):根據index刪除元素並返回index; clear():刪除全部元素; remove(s):從左至右刪除找到的第一個元素,沒找到匹配的元素則ValueError異常; 統計: count(s):統計s出現的次數 排序: sort(reverse=False):升序,能夠指定爲降序 reverse():僅僅顛倒當前列表順序
字典dict經常使用方法以下:
建立字典: {}.fromkeys(iterable,val) 增長或修改: d.update({'k1':'v2'}):若字典d存在鍵k1,則更新其值爲v2;若不存在鍵k1,則增長鍵值對; d.setdefault('k1','v2'):若字典d存在k1,則返回其對應的值,若不存在,則增長鍵值對{'k1':'v2'} 刪除: d.pop('k1'):若k1存在,則刪除該鍵值對,並返回value;若不存在,則報KeyError異常 d.clear():清空字典; d.popitem():隨機刪除鍵值對; 查詢: get('k1','not found') d.keys():結構相似[k1,k2,k3],主要這個不是列表,還須要通過轉換才難成爲列表 d.values():結構相似[v1,v2,v3] d.items():返回結構相似 [(k1,v2),(k2,v2)]
tuple元組類型爲不可變數據類型:
建立字典:tuple(iterable) 統計: count(s) index(s)
集合set類型無序,且不重複:
增長: add(item) s.update(s1) s.union(s1) 刪除: discard(item) 差集: s1中可是s2中沒有的元素:s1.difference(s2) == s1 - s2 交集: s1.intersection(s2) 也能夠運用 +、- 運算符。
函數名=lambda 參數(多個時以逗號隔開):返回值
格式:f=lambda x, y : x*y
,參數能夠有多個,且只能寫一行。
保證程序結構完整,無其餘任何做用。
在函數不肯定有多少個參數時候,能夠採用可變參數。
args:會將接收到的全部的位置參數轉換成列表格式,存放在函數內部做用域內;
kwargs:會將接收到的鍵值對參數轉換成字典格式,存放在函數內部做用域內。
淺拷貝只是增長了一個指針指向一個存在的內存地址。
而深拷貝是增長了一個指針而且從新開闢一個內存空間。
單層數據結構:
import copy # 淺拷貝 li1 = [1, 2, 3] li2 = li1.copy() li1.append(4) print(li1, li2) # [1, 2, 3, 4] [1, 2, 3,4] # 深拷貝 li1 = [1, 2, 3] li2 = copy.deepcopy(li1) li1.append(4) print(li1, li2) # [1, 2, 3, 4] [1, 2, 3]
多層數據結構:
import copy # 淺拷貝 指向共有的地址 li1 = [1, 2, 3,[4,5],6] li2 = li1.copy() li1[3].append(7) print(li1, li2) # [1, 2, 3, [4, 5, 7], 6] [1, 2, 3, [4, 5, 7], 6] # 深拷貝 重指向 li1 = [1, 2, 3,[4,5],6] li2 = copy.deepcopy(li1) li1[3].append(7) print(li1, li2) # [1, 2, 3, [4, 5, 7], 6] [1, 2, 3, [4, 5], 6]
參考:
http://python.jobbole.com/87843/
http://www.cnblogs.com/Xjng/p/5128269.html
python裏每個東西都是對象,當對象多了一個引用,則此對象的(PyObject)的計數變量(ob_refcnt)+1
,反之-1,當ob—refcnt=0
,此對象會被系統回收。
1.一、循環引用:當對象A和B相互引用,可是沒有外部再引用它們任何一個,它們的引用計數雖然都爲1,但顯然應該被回收。
解決循環引用的問題,主要是list、set、dict、instance等容器對象,步驟以下:
I、先標記上全部活動對象
II、再將全部未活動的對象清除
怎麼標記?從根對象(全局變量、調用棧、寄存器)出發,以引用做爲線,來鏈接內存中的對象。
缺點:簡單粗暴,清除非活動對象前必須順序掃描整個堆內存。
將內存根據對象存活的時間由短到長分爲三代:年輕代、中年代、老年代,垃圾回收頻率以此減小,因此老年代的對象可能存活於系統的整個內存空間。
以空間換時間,具體步驟以下:
一、新建立的對象會被存放在年輕代;
二、當鏈表總數(gc計數器)達到上限時,會觸發垃圾回收(gc.collect),將那些非活動對象和循環引用的對象回收,將剩餘的活動對象轉移到中年代;
三、以此類推,活動時間最久的對象最後都保存在老年代,且老年代的回收頻率是最低的。
題目1:
def multipliers(): # 返回包含四個匿名函數的列表 return [lambda x:i*x for i in range(4)] # 注意,若返回生成器,則結果未[0,2,4,6] print([m(2) for m in multipliers()])
結果分析:因爲函數未被調用,循環中的i值未被寫入函數,通過屢次替代,循環結束後i值爲3,
故結果爲:6,6,6,6,此處容易犯錯,不是很好想通。
題目二:現有兩個元組(('a'),('b'))
,(('c'),('d'))
,請使用python中匿名函數生成列表[{'a':'c'},{'b':'d'}]
?
# 一、最笨的辦法 ret = lambda s1,s2:[{s1[0][0]:s2[0][0]},{s1[1][0]:s2[1][0]}] # 二、利用zip先鏈接兩個列表;二、再利用dict構造方法直接生成字典 In [8]: s1 Out[8]: ('a', 'b') In [9]: s2 Out[9]: ('c', 'd') In [10]: zip(s1,s2) Out[10]: <zip at 0x108587c08> In [12]: list(zip(s1,s2)) Out[12]: [('a', 'c'), ('b', 'd')] In [11]: dict(zip(s1,s2)) Out[11]: {'a': 'c', 'b': 'd'} # 利用map(func,iterable),匿名函數能夠結合map使用。 dict(lambda item:list(item),zip(s1,s2)))
filter(func,iterable)
返回一個生成器g,調用g時會遍歷iterable傳入func,並將判斷func(item)若未真,則顯示,未False,則直接過濾掉。
def is_odd(x): return x % 2 == 1 v=list(filter(is_odd, [1, 4, 6, 7, 9, 12, 17])) print(v) #[1, 7, 9, 17]
參數: 都是一個函數名 + 可迭代對象
返回值: 都是返回可迭代對象。
區別:
一、filter 是作篩選的,結果仍是原來就在可迭代對象中的項;
二、map 是對可迭代對象中每一項作操做的,結果不必定是原來就在可迭代對象中的項。
isintance(對象,類)
:判斷一個對象是不是一個已知的類型;
type(對象)
:直接返回給定對象的類型:list,str,dict,等等,不考慮類的繼承關係;
# type() 與 isinstance() 區別 class A: pass class B(A): pass print("isinstance",isinstance(A(),A)) # isinstance True print("type",type(A()) == A) # type True print('isinstance',isinstance(B(),A) ) # isinstance True print('type',type(B()) == A) # type False
zip(*iterable)
會將同時對每一個可迭代對象中的元素按照相同索引則打包成一個個元祖,而後返回由這些元祖組成的列表迭代器,若各個可迭代對象長度不一致,以最短的長度爲準。
print(list(zip([0,1,3],[5,6,7],['a','b']))) # [(0, 5, 'a'), (1, 6, 'b')]
reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])
運算過程:((((1+2)+3)+4)+5)
,屬於累加計算類型(calculatively)。
from functools import reduce def add(x,y): return x + y print(reduce(add,[1,2,3,4,5])) # 15 print(reduce(lambda x, y: x+y, [1,2,3,4,5])) # 15 print(reduce(add,range(1,101))) # 5050
大體結構以下:
1*1=1 2*1=2 2*2=4 3*1=3 3*2=6 3*3=9 ... 9*1=9 9*2=18 9*3=27 ... 9*9=81
# 多行方法,直接print for i in range(1, 10): for j in range(1,i+1): item = '%sx%s=%s' % (i,j,i*j) print(item,end=' ') print() # 先將每一行組裝成一個列表項,最後調用'\n'.join(lst)最後打印出每一項 ret_list=[] for i in range(1, 10): temp = '' for j in range(1,i+1): item = '%sx%s=%s ' % (i,j,i*j) temp += item ret_list.append(temp) print('\n'.join(ret_list)) # 一行代碼 print( '\n'.join( [ ' '.join(['%s*%s=%s' % (j, i, i * j) for j in range(1, i + 1)]) for i in range(1, 10) ] ) )
參考:https://docs.python.org/2.3/ref/comparisons.html
1 < 2 == 2
等價與1<2 and 2==2
(1,)
是tuple類型,可是(1)
是整數類型。
l[start:end:step]
:start表示其實索引,end表示結束索引,step表示步長。
In [46]: l=list('123456789') In [47]: l Out[47]: ['1', '2', '3', '4', '5', '6', '7', '8', '9'] # 表示步長爲2 In [48]: l[::2] Out[48]: ['1', '3', '5', '7', '9'] # 步長爲-1 In [49]: l[::-2] Out[49]: ['9', '7', '5', '3', '1'] # 整個列表 In [50]: l[:] Out[50]: ['1', '2', '3', '4', '5', '6', '7', '8', '9'] # 同上 In [51]: l[::] Out[51]: ['1', '2', '3', '4', '5', '6', '7', '8', '9'] In [52]: l[1:4:2] Out[52]: ['2', '4'] # 結束索引爲-1,不包括-1的值 In [53]: l[:-1] Out[53]: ['1', '2', '3', '4', '5', '6', '7', '8']
棧(stack)和隊列(queue)是兩種數據結構,與具體的語言無關。
它們都屬於線性表結構。
實現棧stack,後進先出,只能在表的一端進行插入和刪除操做,不一樣與隊列queue結構(在表的一端進行插入在另外一端進行刪除)
class Stack(object): def __init__(self): self.items = [] def push(self,item): self.items.append(item) def pop(self): return self.items.pop() def peek(self): return self.items[-1] def is_empty(self): return not bool(len(self.items)) def size(self): return len(self.items) s=Stack() s.push('a') s.push('b') s.push('c') print(s.peek()) print(s.pop()) print(s.pop()) print(s.pop()) print(s.is_empty())
可迭代對象:能夠進行for循環遍歷,內置方法__iter__
,python中的str、list、tuple、dict都是可迭代對象。
生成器:保存的算法,而非數據結構,生成器表達式:(i for i in range(10))
。生成器內置__iter__
和__next__
方法。生成器的函數表達:
def fib(max): n, prev, curr = 1,0, 1 while n<=max: yield prev n+=1 prev, curr = curr, curr + prev ite = fib(10) print(ite) # <generator object fib at 0x10ac3ea98>
迭代器:生成器也是迭代器的一種,且全部可迭代對象也屬於迭代器。
在不改變原函數的基礎上,在函數執行先後進行定製操做。
閉包函數: 一、嵌套函數;二、外層函數返回內層函數;三、內層函數引用外層函數的變量。
優勢:時間複雜度O(logN)
缺點:必須爲有序序列。
def count_time(func): def inner(*args, **kwargs): import time start = time.time() handle=func(*args,**kwargs) end = time.time() print('%s 耗時<%s>'% (func.__name__,(end-start))) return handle return inner @count_time def bin_search(val,arr): # 記錄數組的最高位和最低位 min = 0 max = len(arr) - 1 if val in arr: # 創建一個死循環,直到找到val while True: # 獲得中間索引 mid = int((min + max) / 2) # val在中間值左邊,已經排除mid if val<arr[mid]: max = mid-1 # val在中間值右邊,已經排除mid elif val>arr[mid]: min = mid+1 # val等於中間值 elif arr[mid] == val: return arr[mid] else: print("沒有該數字!") @count_time def common_search(val,arr): for item in arr: if item ==val: return item if __name__ == "__main__": lst = list(range(10000000)) common_search(9999999,lst) bin_search(9999999,lst)
import os for root,holder,files in os.walk('/Users/mac/Desktop/f1'): print('root<%s> holder<%s> files<%s>'% (root,holder,files)) # root爲當前路徑,holder爲當前路徑下的一級文件夾列表,files爲當前路徑下的文件列表 # root < / Users / mac / Desktop / f1 > holder < ['f3', 'f2'] > files < ['.DS_Store', '1'] > # root < / Users / mac / Desktop / f1 / f3 > holder < [] > files < ['3', '2'] > # root < / Users / mac / Desktop / f1 / f2 > holder < [] > files < ['4'] > for f in files: print('%s<%s>'%(os.path.join(root,f),os.path.getsize(os.path.join(root,f))))
os模塊負責程序與操做系統的交互,提供了訪問操做系統底層的接口;
sys模塊負責程序與python解釋器的交互,提供了一系列的函數和變量,用於操控python的運行時環境。
os與sys模塊的官方解釋以下: os: This module provides a portable way of using operating system dependent functionality. 這個模塊提供了一種方便的使用操做系統函數的方法。 sys: This module provides access to some variables used or maintained by the interpreter and to functions that interact strongly with the interpreter. 這個模塊可供訪問由解釋器使用或維護的變量和與解釋器進行交互的函數。 os 經常使用方法 os.remove() 刪除文件 os.rename() 重命名文件 os.walk() 生成目錄樹下的全部文件名 os.chdir() 改變目錄 os.mkdir/makedirs 建立目錄/多層目錄 os.rmdir/removedirs 刪除目錄/多層目錄 os.listdir() 列出指定目錄的文件 os.getcwd() 取得當前工做目錄 os.chmod() 改變目錄權限 os.path.basename() 去掉目錄路徑,返回文件名 os.path.dirname() 去掉文件名,返回目錄路徑 os.path.join() 將分離的各部分組合成一個路徑名 os.path.split() 返回( dirname(), basename())元組 os.path.splitext() 返回 (filename, extension) 元組 os.path.getatime\ctime\mtime 分別返回最近訪問、建立、修改時間 os.path.getsize() 返回文件大小 os.path.exists() 是否存在 os.path.isabs() 是否爲絕對路徑 os.path.isdir() 是否爲目錄 os.path.isfile() 是否爲文件 sys 經常使用方法 sys.argv 命令行參數List,第一個元素是程序自己路徑 sys.modules.keys() 返回全部已經導入的模塊列表 sys.exc_info() 獲取當前正在處理的異常類,exc_type、exc_value、exc_traceback當前處理的異常詳細信息 sys.exit(n) 退出程序,正常退出時exit(0) sys.hexversion 獲取Python解釋程序的版本值,16進制格式如:0x020403F0 sys.version 獲取Python解釋程序的版本信息 sys.maxint 最大的Int值 sys.maxunicode 最大的Unicode值 sys.modules 返回系統導入的模塊字段,key是模塊名,value是模塊 sys.path 返回模塊的搜索路徑,初始化時使用PYTHONPATH環境變量的值 sys.platform 返回操做系統平臺名稱 sys.stdout 標準輸出 sys.stdin 標準輸入 sys.stderr 錯誤輸出 sys.exc_clear() 用來清除當前線程所出現的當前的或最近的錯誤信息 sys.exec_prefix 返回平臺獨立的python文件安裝的位置 sys.byteorder 本地字節規則的指示器,big-endian平臺的值是'big',little-endian平臺的值是'little' sys.copyright 記錄python版權相關的東西 sys.api_version 解釋器的C的API版本 總結: os模塊負責程序與操做系統的交互,提供了訪問操做系統底層的接口; sys模塊負責程序與python解釋器的交互,提供了一系列的函數和變量,用於操控python的運行時環境。
通常有面向過程和麪向對象兩種思想。
面向過程指的是將問題分解,進而流程化,進而簡單化,缺點是可擴展性差。
面向對象是利用類和對象來描述現實世界的全部事物。優勢是複雜度高,缺點是可擴展性強。
類是具備類似屬性和方法的對象的模板,對象是類的實例化,類模板必須通過實例化才能被賦予行爲與特徵。
一、繼承:將多個類的共同屬性和方法封裝到一個類下,而後派生類繼承這個類,就可使用這個類下的全部方法與熟悉,應用場景:django-rest-framework中視圖類的繼承。
二、封裝:將數據屬性與方法封裝到類下,那麼類和類的實例化對象能夠經過.
操做來調用這些方法與數據屬性;還能夠將設置私有屬性和方法,只在類內部調用,限制外部訪問。應用場景:在flask的上下文管理中將session和request封裝到了RequestContext對象中,將app和g封裝到了AppContext對象中。
三、多態:同一個事物的多種形態,具體指的是基類的不一樣方法在派生類中有着不一樣的實現方式。
# __init__() 初始化 # __new() 建立對象 # __call__() 類A的實例化對象a加()會調用A中的__call__()方法 # __del__ 析構方法,當對象在內存中被釋放時,自動觸發執行。如當 del obj 或者應用程序運行完畢時,執行該方法裏邊的內容。 # __enter__和__exit__ 出現with語句,對象的__enter__被觸發,有返回值則賦值給as聲明的變量;with中代碼塊執行完畢時執行__exit__裏邊的內容。 class Message(object): def __init__(self,name,mode): self.name = name self.mode = mode def __enter__(self): print("打開文件<%s>..." % self.name) self.filehander = open(self.name,self.mode) return self.filehander def __exit__(self,*para): print("關閉文件<%s>.."%self.name) self.filehander.close() with Message('1.txt','rb') as f: for i in f: print(i) # __module__:表示當前操做的對象在那個模塊 obj.__module__ class A: def __init__(self): print('A>>',self.__class__) pass class B(A): def __init__(self): print('B>>',self.__class__) super().__init__() b = B() # __doc__:類的描述信息,該描述信息沒法被繼承 # __str__:改變對象的字符串顯示 print函數 --->obj.__str__() # __repr__:改變對象的字符串顯示 交互式解釋器 --->obj.__repr__() # __format__:自定製格式化字符串 # __slots__:一個類變量 用來限制實例能夠添加的屬性的數量和類型 # 本質上操做的是obj.__dict__這個字典 __getattr__():obj.xx __setattr__(): __delattr__(): __getitem__():obj[xxx] __setitem__() __delitem__() __mro__():查找繼承順序時使用 __str__(): __repr__(): __iter__(): __dict__(): __add__():
主要用於 子類 繼承 基類 的方法。對於單繼承,直接調用當前類的父類的對應的方法,對於多繼承關係,super(cls, inst) 得到的是 cls 在 inst 的 MRO 列表中的下一個類。
參考:http://www.javashuo.com/article/p-vkkhxbec-bt.html
# 多繼承關係示例 class Base: def __init__(self): print('in Base') class A(Base): def __init__(self): super(A,self).__init__() print('in A...') class B(Base): def __init__(self): super(B,self).__init__() print('in B...') class C(A,B): def __init__(self): # [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, # <class '__main__.Base'>, <class 'object'>] print(C.mro()) super(C,self).__init__() print('in C...') c = C()
具體流程以下圖所示:
import functools def deco(func): @functools.wraps(func) # 加在最內層函數正上方 def wrapper(*args, **kwargs): print('in wrapper...') return func(*args, **kwargs) return wrapper @deco def index(): """doc說明""" print('in index...') index() print('name<%s> doc<%s>'%(index.__name__,index.__doc__)) # 沒有加@functools.wraps(func)裝飾:name<wrapper> doc<None> # 加以後:name<index> doc<doc說明>
自動傳入self的method方法;手動傳入對象的function函數。
class B: def run(self): pass @staticmethod def eat(): pass @classmethod def sleep(cls): pass b = B() print(b.run) # 對象的方法 <bound method B.run of <__main__.B object at 0x10d19f2b0>> print(b.eat) # 函數<function B.eat at 0x10d1918c8> print(b.sleep) # 類B的方法<bound method B.sleep of <class '__main__.B'>> from types import FunctionType,MethodType print(isinstance(b.run, MethodType)) # True print(isinstance(b.eat, FunctionType)) # True
class Num: # 普通方法:能用Num調用而不能用實例化對象調用 def one(): print ('1') # 實例方法:能用實例化對象調用而不能用Num調用 def two(self): print ('2') # 靜態方法:能用Num和實例化對象調用 @staticmethod def three(): print ('3') # 類方法:第一個參數cls長什麼樣不重要,都是指Num類自己,調用時將Num類做爲對象隱式地傳入 @classmethod def go(cls): cls.three()
from multiprocessing import Queue,Manager,Pipe # Queue:隊列,put()、get() q=Queue() # Pipe:主進程和子進程之間能夠實現收發消息。 father_conn,son_conn=Pipe() # Manager: with Manager() as manager: D=manager.dict() # 生成一個字典,可在多進程間共享和傳遞 L=manager.list() # 生成一個列表
計算機組成:硬件層、操做系統(負責將硬件層封裝起來,以接口的形式提供給咱們使用)、app。
以一個應用軟件爲例,它自己就是一個程序,雙擊開啓軟件會開啓多個進程,每一個進程內部可能會有多個線程。
線程是一個進程內的執行單元。
線程和進程的區別:建立新的進程開銷大,須要開闢度獨立的內存空間,而一個進程內至少有一個線程,且當前進程內的全部線程共享當前進程的內存空間,因此建立新線程開銷小;
多進程並行對於計算型任務處理效率高,而多線程能夠實現併發,遇到IO操做會來回切換,適合處理阻塞性任務;
協程與線程:
(1)一個線程能夠有多個協程,一個進程也能夠單獨擁有多個協程,這樣Python中則能使用多核CPU;
(2)線程進程都是同步機制,而協程是異步;
(3)協程能保留上一次調用時的狀態。
Global Interpreter Lock,全局解釋器鎖,保證同一時刻同一進程中只能有一個線程被cpu執行,例如一個進程內也存在垃圾回收線程,若垃圾回收線程要回收變量,而其餘線程要修改變量,就會產生衝突,因此須要GIL🔒的存在,保證同一時刻同一個進程中只有線程拿到解釋器執行權限。
單線程下實現併發效果。多路複用是在單個線程中經過記錄每一個IO流的狀態來同時管理多個IO流。至關於機場管理系統,經過記錄每架飛機的狀態來進行調度管理。
select和poll單線程下實現監聽多個客戶,可是系統不會通知,只能每次循環遍歷文件描述符(fd)表來判斷哪一個就緒。select有最大監聽數量限制1024,而poll是基於鏈表進行fd管理的。
epoll有函數回掉機制,直接通知應用程序哪一個fd就緒,減小了輪訓操做。
參考:http://www.javashuo.com/article/p-cntwfxgr-eb.html
參考博客:https://blog.csdn.net/u012351051/article/details/83352021
從應用產生數據到主機將數據發送出去的逐層對數據封裝的過程:
(IP 數據包在以太網數據包裏面,TCP 數據包在 IP 數據包裏面)
屬於程序員與應用程序打交道。app會根據http協議(URL:請求頭、請求體)解析傳過來的TCP數據包,反過來就是根據http協議封裝數據到tcp包中。
利用TCP、UDP協議,實現數據穩定性傳輸。
TCP的最大實際負載爲1400Bytes,因此當數據很大,會分多個包發送,且每一個包都帶有seq序列號。TCP 數據包裏面有一個端口(port)參數,就是用來指定轉交給監聽該端口的應用程序。TCP主要用於瀏覽器(http、https、ftp等協議)、郵件(POP、SMTP)。特色是:
一、數據包丟失處理(確認 以及 重傳機制),例如A發送多個數據包才能完整傳輸數據。當發送第一個包(seq=1,8bytes_data),B返回應該返回(ack=9);若第二個包(seq=2,12bytes——data)丟包,B沒收第二個數據包則每次都返回(ack=9),直到B連續三次返回ack=9,那麼會通知A再次發送第二個數據包(seq=2,12bytes_data),以此保證數據的完整性,圖示以下:
二、三次握手創建鏈接,四次揮手斷開鏈接,也保證了數據傳輸的穩定可靠。缺點是不但即耗時,也會佔用系統cpu和內存資源。
UDP主要用於QQ語音、QQ視頻等。
優勢有:
一、只要有對方的IP和port便可發送數據,效率更高;
二、能夠多對多交互通信,可是TCP只能是一對一通信;
三、沒有擁塞機制(網絡出現擁塞,不會致使源主機發送速率下降),經常使用於IP電話、實時視頻會議等。
缺點有:
一、可能產生丟包,且不能保證數據順序,因此只能傳輸少許數據;
二、head只有8bytes。
IP地址規定了局域網之間的互通,容許某個局域網的A主機向另外一個局域網的B主機發送消息。
Ethernet協議:規定電信號如何組成packet,只能解決局域網內點對點的通信。
head(18bytes):本機mac(6bytes)+目標機mac(6bytes)+數據描述(6bytes)
data(46-1500bytes):真正的包裹。
路由級別的數據傳輸。
SYN(synchronize sequence number),同步序列號,SYN=1表示須要創建TCP鏈接;ACK(acknowledgement),確認信號;Seq=x是隨機生成的序列號。
具體步驟:
一、客戶機A發送SYN=1,Seq=X(隨機生成);
二、服務端B發送SYN+ACK報文,ACK=X+1(根據客戶機發送的seq而定),Seq=Y;
三、客戶機A發送ACK,ACK=Y+1,seq=Z以此創建鏈接。
參考:http://blog.51cto.com/10642812/2286552
一、主動斷開方發送FIN(seq=X,ack=212,FIN=1),請求斷開鏈接,不會再發送數據給被動方;
二、被動方發送ACK(seq=Y,ACK=X+1),表示收到斷開鏈接請求,且再也不發送數據;
三、被動方發送FIN(seq=Z,FIN=1,ack=Y+1),請求斷開鏈接,保證發送的數據A已經徹底收到(確認重傳機制);
四、主動方發送ACK(seq=W,ack=Z+1);
斷開過程詳細過程:
(1)主機A發送斷開TCP鏈接請求的報文,其中報文中包含seq序列號,是有發送端隨機生成的,而且還將報文中FIN字段的值設爲1,表示須要斷開TCP鏈接。
(2)主機B會回覆A發送的TCP斷開請求報文,其中包含seq序列號,是由恢復段隨機生成的,並且會產生ACK字段,ACK字段的數值,是在A發送過來的seq序列號基礎上加1進行回覆的,以便A收到信息時,知曉本身的TCP斷開請求已獲得了驗證。
(3)在主機B回覆完A的TCP斷開請求後,不會立刻就進行TCP鏈接的斷開,主機B先會確認確保斷開前,全部傳輸到A的數據是否已經傳輸完畢,一旦確認傳輸完畢就會將回復報文的FIN字段置爲1,併產生隨機seq序列號。
(4)主機A收到主機B的TCP斷開請求後,會回覆主機B 的斷開請求,包含隨機生成的seq字段和ack字段,ack字段會在主機B的TCP斷開請求的seq的基礎上加1,從而完成主機B請求的驗證回覆。
路由器:能夠實現局域網之間的通信;
交換機:能夠實現局域網內部通信。
地址解析協議(Address Resolution Protocol),根據IP地址獲取物理mac地址的一個TCP/IP協議。
經過DNS服務器來解析域名和IP的對應關係,將域名變成IP地址。
Socket是應用層與TCP/IP協議族通訊的中間軟件抽象層,它是一組接口。
在設計模式中,Socket其實就是一個門面模式,它把複雜的TCP/IP協議族隱藏在Socket接口後面,對用戶來講,一組簡單的接口就是所有。
服務端:
一、建立socket對象;
二、綁定ip端口bind();
三、設置最大連接數listen();
四、accept()與客戶端的connect()建立雙向管道,等到聯接;
五、send(), recv(), 收發數據;
六、close()。
客戶端:
一、建立socket對象;
二、connect()與服務端accept()建立雙向管道;
三、send()、recv();
五、close()。
在不知道數據大小的狀況下,接收端會按照指定的長度從系統內存中取出數據,若指定的長度小於數據長度,那麼多餘的數據會遺留在系統內存中,下此再取數據時候會優先被取出。
解決粘包問題:若果能夠預先知道要接受的數據大小,就能夠徹底解決接收數據的粘包問題。
內容分發網絡,content delivery network。
目的是使用戶能夠就近到服務器取得所需內容,解決 Internet網絡擁擠的情況,提升用戶訪問網站的響應速度。
Linux virtual server,主要用於多服務器的負載均衡,可用於請求的分發、緩存、業務處理。
一、工做在網絡層,能夠實現高性能,高可用的服務器集羣技術;
二、把許多低性能的服務器組合在一塊兒造成一個超級服務器;
三、易用,配置很是簡單,且有多種負載均衡的方法;
四、它穩定可靠,即便在集羣的服務器中某臺服務器沒法正常工做,也不影響總體效果;
五、另外可擴展性也很是好。
Nginx是一款輕量級的Web、反向代理、郵件服務器,其特色是佔有內存少,併發能力強。
從單一的的服務器到服務器集羣,包括轉發服務器羣、業務服務器羣,且具備故障轉移能力,當其中轉發服務器或業務服務器其中有一臺發生故障或從故障恢復,那麼沒有影響(Keepalived)。
參考:
https://blog.csdn.net/guchuanyun111/article/details/52056474
http://www.javashuo.com/article/p-yaxbpwde-z.html
關係型數據庫(須要有表結構):mysql、oracle 、 sqlserver、db二、sybase。
非關係型數據庫(是以key-value存儲的,沒有表結構)(NoSQL):
一、MongoDB:一個高性能,開源,無模式的文檔型數據庫,開發語言是C++,它在許多場景下可用於替代傳統的關係型數據庫或鍵/值存儲方式;
二、Redis:一個開源的使用C語言編寫、支持網絡、可基於內存或持久化的日誌型、Key-Value數據庫,並提供多種語言的API。目前由VMware主持開發工做。
一、InnoDB
支持事務
支持表鎖、行鎖(for update)
# 表鎖,當沒有commit以前,此表被🔒定,另外一終端沒法使用此表 begin; select * from tb for update commit; # 行鎖 select id,name from tb where id=2 for update
二、myisam
查詢速度快
全文索引
支持表鎖:select * from tb for update
。
三、NDB:高可用、 高性能、高可擴展性的數據庫集羣系統
四、Memory:默認使用的是哈希索引
數據庫的三大特性:表、表中的數據(字段)、表與表之間的關係。
數據庫設計三大範式:
一、確保每列保持原子性(即數據庫表中的全部字段值是不可分解的原子值);
二、確保表中的每列都是和主鍵相關(表中只能保存一種數據,不能夠把多種數據保存在同一張表中)--->徹底屬於當前表的數據;
三、確保每列都和主鍵直接相關,而不是間接相關(在一個數據庫表中保存的數據只能與主鍵相關)----> 消除傳遞依賴(間接)。
好比在設計一個訂單數據表的時候,能夠將客戶編號做爲一個外鍵和訂單表創建相應的關係,而不能夠在訂單表中添加關於客戶其它信息(好比姓名、所屬公司等)的字段。
數據庫五大約束:
一、primary KEY:設置主鍵約束;
二、UNIQUE:設置惟一性約束,不能有重複值;
三、DEFAULT 默認值約束;
四、NOT NULL:設置非空約束,該字段不能爲空;
五、FOREIGN key :設置外鍵約束。
事務(失誤)用於將多個SQL做爲原子性操做,一旦有某一個出現錯誤,便可回滾到原來的狀態,從而保證數據庫數據完整性。
事務的特性:
一、原子性: 確保工做單元內的全部操做都成功完成,不然事務將被停止在故障點,和之前的操做將回滾到之前的狀態。
二、一致性: 確保數據庫正確地改變狀態後,成功提交的事務。
三、隔離性: 使事務操做彼此獨立的和透明的。
四、持久性: 確保提交的事務的結果或效果的系統出現故障的狀況下仍然存在。
InnoDB支持事務,MyISAM不支持。
啓動事務:
start transaction; update from account set money=money-100 where name='a'; update from account set money=money+100 where name='b'; commit;
FK(一對多):下拉框裏面的數據就須要用FK關聯另外一張表。
M2M(多對多):多選的下拉框,或者checkbox。
觸發器:對數據庫某張表的增長、刪除,修改的先後定義一些操做。
函數:觸發函數是經過select。聚合函數(max/sum/min/avg),時間格式化(date_format),字符串拼接(concat)。
存儲過程:將SQL語句保存到數據庫中,並命名,之後在代碼調用時,直接調用名稱便可。參數類型有in(只將參數傳進去)、out(只拿結果)、inout(既能夠傳,能夠取)。
函數與存儲過程區別:本質上沒區別,只是函數有如:只能返回一個變量的限制,而存儲過程能夠返回多個;函數是能夠嵌入在sql中使用的,能夠在select中調用,而存儲過程不行。
視圖:一個虛擬表,不是真實存在的(只能查,不能改)。
一、單列:
1.一、普通索引index:加速查找
1.二、惟一索引unique:加速查找 + 約束:惟一(只能有一個空,否則就重複了)
1.三、主鍵(primay key):加速查找 + 約束(惟一 + 不能爲空)
二、多列:
2.一、聯合索引(多個列建立索引),例如 index(id,name)
2.二、聯合惟一索引,例如 unique(id,name)
2.三、聯合主鍵索引:例如primary key(id,name)
聯合索引遵循最左前綴的規則,不然沒法命中索引。
索引合併:利用多個單例索引查詢,例如:在數據庫查用戶名和密碼,分別給用戶名和密碼創建索引。
覆蓋索引:在索引表中就能將想要的數據查詢到。
主鍵是能肯定一條記錄的惟一標示,例如:身份證證號。
外鍵是用於與另外一張表的關聯,是能肯定另外一張表記錄的字段,用於保持數據的一致性。
主鍵:惟一標識一條記錄,不能有重複的,不容許爲空。
外鍵:另外一張表的主鍵,外鍵能夠有重複的,能夠爲空。
做用不一樣:用來保證數據完整性 用來與其餘表創建聯繫的
個數不一樣:主鍵只能有一個,而外鍵一個表能夠有多個外鍵。
1.- like '%xx' select * from tb1 where name like '%cn'; 2.- 使用函數 select * from tb1 where reverse(name) = 'wupeiqi'; 3.- or select * from tb1 where nid = 1 or email = 'seven@live.com'; 特別的:當or條件中有未創建索引的列才失效,如下會走索引 select * from tb1 where nid = 1 or name = 'seven'; select * from tb1 where nid = 1 or email = 'seven@live.com' and name ='alex' 4.- 類型不一致 若是列是字符串類型,傳入條件是必須用引號引發來,否則... select * from tb1 where name = 999; 5.- != select * from tb1 where name != 'alex' 特別的:若是是主鍵,則仍是會走索引 select * from tb1 where nid != 123 6.- > select * from tb1 where name > 'alex' 特別的:若是是主鍵或索引是整數類型,則仍是會走索引 select * from tb1 where nid > 123 select * from tb1 where num > 123 7.- order by select email from tb1 order by name desc; 當根據索引排序時候,選擇的映射若是不是索引,則不走索引 特別的:若是對主鍵排序,則仍是走索引: select * from tb1 order by nid desc; 8.- 組合索引最左前綴 若是組合索引爲:(name,email) name and email -- 使用索引 name -- 使用索引 email -- 不使用索引
什麼是慢日誌? MySQL的慢查詢日誌是MySQL提供的一種日誌記錄,它用來記錄在MySQL中響應時間超過閥值的語句,具體指運行時間超過long_query_time值的SQL,
修改配置文件:
slow_query_log = OFF # 是否開啓慢日誌記錄 long_query_time = 2 # 時間限制,超過此時間,則記錄 slow_query_log_file = /usr/slow.log # 日誌文件 log_queries_not_using_indexes = OFF # 爲使用索引的搜索是否記錄
下面是開啓:
slow_query_log = ON long_query_time = 2 log_queries_not_using_indexes = OFF log_queries_not_using_indexes = ON # 注:查看當前配置信息: show variables like '%query%' # 修改當前配置: set global 變量名 = 值
能夠參考:
http://www.javashuo.com/article/p-qbuarjcz-k.html
導出現有數據庫數據:
mysqldump -u用戶名 -p密碼 數據庫名稱 >導出文件路徑 # 結構+數據 mysqldump -u用戶名 -p密碼 -d 數據庫名稱 >導出文件 路徑 # 結構
導入現有數據庫數據:mysqldump -uroot -p密碼 數據庫名稱 < 文件路徑
一、建立數據表時把固定長度的放在前面;
二、將固定數據放入內存: 例如:choice字段 (django中有用到,數字一、二、3…… 對應相應內容)
三、char 和 varchar 的區別(char可變, varchar不可變 )
四、聯合索引遵循最左前綴(從最左側開始檢索);
五、避免使用 select * ;
六、讀寫分離:兩臺服務器同步數據,利用數據庫的主從分離(主 用於刪除、修改、更新;從 用於查);
七、分庫:當數據庫中的表太多,將某些表分到不一樣的數據庫,例如:1W張表時,缺點是連表查詢。
八、分表:
- 水平分表:將記錄選擇性地存放到對應的表中。避免一張表出現幾百萬條數據,縮短了一條sql的執行時間,例如聊天信息,會講將每一個人的聊天記錄分別存放到各自的記錄表中,這樣須要查詢的時候,只須要從本身的記錄表中查詢便可;
- 垂直分表:拆分表,將經常使用的字段和不經常使用且數據量大的字段分別存放在兩種表中。將一個表中不常常用到的,或者像text這種類型比較大的字段挪到一個表中,其餘經常使用的(訪問頻繁的)字段單獨一個表,兩張表再經過外鍵關聯起來。
- 參考:http://www.javashuo.com/article/p-gzlwpvgq-bb.html
九、加緩存:利用redis、memcache (經常使用數據放到緩存裏,提升取數據的速度)
十、若是隻想獲取一條數據:select * from tb where name=‘alex’ limit 1;
查看有沒有命中索引,讓數據庫幫看看運行速度快不快:explain select * from table;
緣由:limit 1000000,20
的意思掃描知足條件的1000020行,扔掉前面的100w行,返回最後的20行。
解決辦法:
一、子查詢優化法:先找出第一條數據,而後大於等於這條數據的id就是要獲取的數據:
Query_ID: 2 Duration: 0.00167000 Query: select * from Member limit 10, 100 *************************** 3. row *************************** Query_ID: 3 Duration: 0.00112400 Query: select * from Member where MemberID >= (select MemberID from Member limit 10,1) limit 100 *************************** 4. row *************************** Query_ID: 4 Duration: 0.00263200 Query: select * from Member limit 1000, 100 *************************** 5. row *************************** Query_ID: 5 Duration: 0.00134000 Query: select * from Member where MemberID >= (select MemberID from Member limit 1000,1) limit 100 *************************** 6. row *************************** Query_ID: 6 Duration: 0.09956700 Query: select * from Member limit 100000, 100 *************************** 7. row *************************** Query_ID: 7 Duration: 0.02447700 Query: select * from Member where MemberID >= (select MemberID from Member limit 100000,1) limit 100
從結果中能夠得知,當偏移1000以上使用子查詢法能夠有效的提升性能。
二、倒排表優化法: 倒排表法相似創建索引,用一張表來維護頁數,而後經過高效的鏈接獲得數據。缺點是隻適合數據數固定的狀況,數據不能刪除,維護頁表困難。
詳情參考:https://www.jb51.net/article/85312.htm
一、redis不只支持簡單的key_value類型,還支持字典(hash)、字符串、列表、集合、有序集合類型。
二、內存使用效率對比:使用簡單的key-value存儲的話,Memcached的內存利用率更高而若是Redis採用hash結構來作key-value存儲,因爲其組合式的壓縮,其內存利用率會高於Memcached;
三、性能對比:因爲Redis只使用單核,而Memcached可使用多核,因此平均每個核上Redis在存儲小數據時比Memcached性能更高;而在100k以上的數據中,Memcached性能要高於Redis;
四、Redis雖然是基於內存的存儲系統,可是它自己是支持內存數據的持久化的,並且提供兩種主要的持久化策略:RDB快照和AOF日誌;而memcached是不支持數據持久化操做的。
五、集羣管理不一樣,Memcached自己並不支持分佈式,所以只能在客戶端經過像一致性哈希這樣的分佈式算法來實現Memcached的分佈式存儲。
Redis默認支持16個數據庫,能夠經過配置databases來修改這一數字。客戶端與Redis創建鏈接後會自動選擇0號數據庫,不過能夠隨時使用SELECT命令更換數據庫。
Redis支持多個數據庫,而且每一個數據庫的數據是隔離的不能共享,而且基於單機纔有,若是是集羣就沒有數據庫的概念。
RDB是在某個時間點將數據寫入一個臨時文件,持久化結束後,用這個臨時文件替換上次持久化的文件,達到數據恢復。
AOF:把全部命令保存起來,若是想到從新生成到redis,那麼就要把命令從新執行一次。
參考;http://www.javashuo.com/article/p-bcqjvlpc-z.html
redis集羣、分片、分佈式redis redis-py-cluster 集羣方案: - redis cluster 官方提供的集羣方案。 - codis,豌豆莢技術團隊。 - tweproxy,Twiter技術團隊。 redis cluster的原理? - 基於分片來完成。 - redis將全部能放置數據的地方建立了 16384 個哈希槽。 - 若是設置集羣的話,就能夠爲每一個實例分配哈希槽: - 192.168.1.20【0-5000】 - 192.168.1.21【5001-10000】 - 192.168.1.22【10001-16384】 - 之後想要在redis中寫值時, set k1 123 將k1經過crc16的算法,將k1轉換成一個數字。而後再將該數字和16384求餘,若是獲得的餘數 3000,那麼就將該值寫入到 192.168.1.20 實例中。
相關知識:redis 內存數據集大小上升到必定大小的時候,就會施行數據淘汰策略(回收策略)。redis 提供 6種數據淘汰策略:
一、volatile-lru:從已設置過時時間的數據集(server.db[i].expires)中挑選最近最少使用的數據淘汰;
二、volatile-ttl:從已設置過時時間的數據集(server.db[i].expires)中挑選將要過時的數據淘汰;
三、volatile-random:從已設置過時時間的數據集(server.db[i].expires)中任意選擇數據淘汰;
四、allkeys-lru:從數據集(server.db[i].dict)中挑選最近最少使用的數據淘汰;
五、allkeys-random:從數據集(server.db[i].dict)中任意選擇數據淘汰;
六、no-enviction(驅逐):禁止驅逐數據。
瀏覽器本質:socket客戶端遵循Http協議
HTTP協議本質:經過\r\n
分割的規範+請求響應以後斷開連接(無狀態、短鏈接)
具體:
Http協議是創建在tcp之上的,是一種規範,它規範定了發送的數據的格式,然而這個數據格式是經過\r\n 進行分割的,請求頭與請求體也是經過2個\r\n分割的,響應的時候,響應頭與響應體也是經過\r\n分割,而且還規定已請求已響應就會斷開連接,即短鏈接、無狀態。
http1.1版本有keepalived的請求頭,一次TCP鏈接中能夠持續發送多份數據而不會斷開鏈接,經過使用keep-alive機制,能夠減小tcp鏈接創建次數。可是,keep-alive並非免費的午飯,長時間的tcp鏈接容易致使系統資源無效佔用。配置不當的keep-alive,有時比重複利用鏈接帶來的損失還更大。因此,正確地設置keep-alive timeout時間很是重要。
keepalive_timout時間值意味着:一個http產生的tcp鏈接在傳送完最後一個響應後,還須要hold住keepalive_timeout秒後,纔開始關閉這個鏈接。
參考博客:http://www.javashuo.com/article/p-sqsgpppe-bd.html
具體流程以下:
請求流程走向以下:
一、wsgi:就是socket服務端,用於接受用戶請求,並進行初次封裝,而後將請求交給web框架(flask、django);
二、中間件:幫助咱們對請求進行校驗或在請求中添加其餘相關數據,例如 csrf、request.session;
三、路由匹配:url和視圖函數或類的映射表;
四、視圖函數:在視圖函數中進行業務邏輯的處理,可能涉及到ORM(數據庫交互組件)、templates 渲染;
六、中間件:對響應的數據進行處理;
七、wsgi:將響應的內容發送給瀏覽器。
也是基於tcp的三次握手和四次揮手。
相比HTTP長鏈接,WebSocket有如下特色:
一、是真正的全雙工方式,創建鏈接後客戶端與服務器端是徹底平等的,能夠互相主動請求。而HTTP長鏈接基於HTTP,是傳統的客戶端對服務器發起請求的模式,服務端永遠是被動的;
二、HTTP長鏈接中,每次數據交換除了真正的數據部分外,服務器和客戶端還要大量交換HTTP header,信息交換效率很低。Websocket協議經過第一個request創建了TCP鏈接以後,以後交換的數據都不須要發送 HTTP header就能交換數據,這顯然和原有的HTTP協議有區別因此它須要對服務器和客戶端都進行升級才能實現(主流瀏覽器都已支持HTML5)。此外還有 multiplexing(多路複用)、不一樣的URL能夠複用同一個WebSocket鏈接等功能。這些都是HTTP長鏈接不能作到的。
web通信的改進方式:
一、輪詢:
以頻繁請求方式來保持客戶端和服務端的同步,可是若服務端的數據無變化,會形成通訊低效。
二、長輪詢:
當服務端沒有數據更新的時候,鏈接會保持一段時間週期直到數據或者狀態改變或者過時,依次減小無效的客戶端和服務端的交互。且當服務端數據變動頻繁的話,這種機制和定時輪詢毫無區別。
參考大神們的回答:
https://www.zhihu.com/question/20215561
https://zhuanlan.zhihu.com/p/23386938
輪詢:經過定時器讓程序每隔n秒執行一次操做。
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> </head> <body> <h1>請選出最帥的男人</h1> <ul> {% for k,v in gg.items() %} <li>ID:{{ k }}, 姓名:{{ v.name }} ,票數:{{ v.count }}</li> {% endfor %} </ul> <script> setInterval(function () { location.reload(); },2000) </script> </body> </html>
跨域廣義上指的是指一個域下的文檔或腳本試圖去請求另外一個域下的資源。
廣義的跨域:
一、資源跳轉: a連接、location重定向、form表單提交;
二、資源嵌入:<link>、<script>、<img>、<frame>
等dom標籤,還有樣式中background:url()
、@font-face()
等文件外鏈;
三、腳本請求: js發起的ajax請求、dom和js對象的跨域操做等。
狹義上指的是瀏覽器的同源策略,即協議、域名、端口必須一致纔算同源,才能互相訪問,不然就算跨域且不能訪問。
一般爲了減輕web服務器的負載,咱們把js、css,img等靜態資源分離到另外一臺獨立域名的服務器上,在html頁面中再經過相應的標籤從不一樣域名下加載靜態資源,而被瀏覽器容許,基於此原理,咱們能夠經過動態建立script,再請求一個帶參網址實現跨域通訊。
在響應頭重設置Access-Control-Allow-Origin便可:
class CORSMiddleware(MiddlewareMixin): def process_response(self,request,response): # 容許你的域名來獲取個人數據 response[' '] = "*" # 容許你攜帶Content-Type請求頭, response['Access-Control-Allow-Headers'] = "Content-Type" # 容許你發送DELETE,PUT response['Access-Control-Allow-Methods'] = "DELETE,PUT" return response
瀏覽器將CORS請求分紅兩類:簡單請求和賦複雜請求。
簡單請求(同時知足如下兩大條件)
一、請求方法是如下三種方法之一:HEAD、GET、POST
二、HTTP的頭信息不超出如下幾種字段:
Accept Accept-Language Content-Language Last-Event-ID Content-Type :只限於三個值application/x-www-form-urlencoded、multipart/form-data、text/plain
凡是不一樣時知足上面兩個條件,就屬於非簡單請求。
列舉Http請求中常見的請求方式:
GET、POST、 PUT、patch(修改數據) HEAD(相似於get請求,只不過返回的響應中沒有具體的內容,用於獲取報頭) DELETE
列舉Http請求中的狀態碼:
1** 信息,服務器收到請求,須要請求者繼續執行操做 2** 成功,操做被成功接收並處理 3** 重定向,須要進一步的操做以完成請求 4** 客戶端錯誤,請求包含語法錯誤或沒法完成請求 5** 服務器錯誤,服務器在處理請求的過程當中發生了錯誤
Http請求中常見的請求頭:
user-agent host referer cookie content-type
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <title>測試</title> </head> <body> <script> var name = 'jack'; function fun() { var name='alex'; function inner() { alert(name) } return inner } // 相似函數裝飾器 var ret = fun(); ret() // 輸出 ‘alex’ </script> </body> </html>
django是大而全的框架,它的內部組件比較多,內部提供 ORM、Admin、中間件、Form、ModelForm、Session、緩存、信號、CSRF。
flask是微型框架,內部組件就比較少了,可是有不少第三方組件來擴展它,好比說有那個wtform(與django的modelform相似,表單驗證)、flask-sqlalchemy(操做數據庫的)、flask-session、flask-migrate、flask-script、blinker可擴展強,第三方組件豐富。因此對他自己來講有那種短小精悍的感受。
django和flask的共同點:兩個框架都沒有寫socket,因此他們都是利用第三方模塊wsgi。
django和flask的區別:
一、內部使用的wsgi也是有些不一樣的:django自己運行起來使用wsgiref,而flask使用werkzeug wsgi。
二、請求管理不太同樣:django是經過將請求封裝成request對象,再經過參數傳遞,而flask是經過上下文管理機制。
Tornado是一個輕量級的Web框架,異步非阻塞 + 內置WebSocket功能。能夠經過一個線程處理N個併發請求(處理IO)。內部組件:內部本身實現socket、路由系統、視圖、模板、cookie、csrf。
做用:一、對用戶請求的數據進行校驗;二、生成HTML標籤。
form對象是一個可迭代對象。
choice的數據若是從數據庫獲取可能會形成數據沒法實時更新。
from django.forms import Form from django.forms import fields from django.forms.models import ModelChoiceField class UserForm(Form): name = fields.CharField(label='用戶名',max_length=32) email = fields.EmailField(label='郵箱') ut_id = ModelChoiceField(queryset=models.UserType.objects.all()) # 依賴 class UserType(models.Model): title = models.CharField(max_length=32) def __str__(self): return self.title
django的信號其實就是django內部爲開發者預留的一些自定製功能的鉤子。
只要在某個信號中註冊了函數,那麼django內部執行的過程當中就會自動觸發註冊在信號中的函數。
pre_init # django的model執行其構造方法前,自動觸發 post_init # django的model執行其構造方法後,自動觸發 pre_save # django的model對象保存前,自動觸發 post_save # django的model對象保存後,自動觸發
場景:
在數據庫某些表中添加數據時,能夠進行日誌記錄。
防止用戶直接向服務端發起POST請求。
對全部的post請求作驗證,將django生成的一串字符串發送給咱們,一種是從請求體發過來,一種是放在隱藏的標籤裏面用的是process_view
方案:先發送GET請求時,將token保存到:cookie、Form表單中(隱藏的input標籤),
之後再發送請求時只要攜帶過來便可。
ContentType contenttype是django的一個組件(app), 爲咱們找到django程序中全部app中的全部表並添加到記錄中。 可使用他再加上表中的兩個字段實現:一張表和N張表建立FK關係。 - 字段:表名稱 - 字段:數據行ID 應用:路飛表結構優惠券和專題課和學位課關聯。