python后端知识点的自我复习
目錄
python知識點
數據結構
Linux操作系統
計算機網絡
mysql數據庫
緩存redis:內存數據庫
web知識點
python知識點
python特點:
(1)python是動態強類型語言,強語言不會發生隱式的類型轉換
(2)膠水語言,輪子多,應用廣泛
(3)性能問題,代碼維護問題,python2、3兼容問題
(4)python中一切皆對象
python2/3之間的差異:
(1)print改為函數,python2中是一個關鍵字
(2)編碼,python3不再有unicode對象,默認str就是unicode
(3)除法,python3返回浮點數
(4)3中可以用super()直接調用父類函數
(5)高級解包,*args、**kwargs,分別返回tuple、dict
(6)新增,yield產生生成器,內置庫asyncio、enum、mock、ipaddress、concurrent.futures等
python函數傳遞:
(1)傳遞可變類型參數
def do_ls(l):l.append(0)print(l)l = [] # 執行結果 do_ls(l) # [0] do_ls(l) # [0,0] do_ls(l) # [0,0,0](2)傳遞不可變類型參數
def do_str(s):s += "a"print(s)s = "hh" # 執行結果 do_str(s) # hha do_str(s) # hha?因為在python中,對一個變量賦值,只是將對象的引用賦給變量,比如:a=1,本質上是1這個對象的引用賦予了a。回到上面的解析,傳遞可變參數給函數的時候,本質上將可變參數的引用傳入函數,所以在函數內使用的變量引用和外部的是一樣的,又因為是參數是可變類型,所以在函數內部發生修改時,外部的變量也一樣發生改變。不可變類型的參數,之所以沒有變化,是因為引用指向了其他對象。
def do_str(s):print("這是剛剛傳入的s,id為:", id(s)) # 這是剛剛傳入的s,id為: 140338339314032s += "a"print("這是發生改變后的s, id為:", id(s)) # 這是發生改變后的s, id為: 140338338859376print(s)s = "hh" print("這是外部s, id為:", id(s)) # 這是外部s, id為: 140338339314032 # 執行結果 do_str(s) # hha def do_ls(s):print("這是剛剛傳入的s,id為:", id(s)) # 這是剛剛傳入的s,id為: 139688067340160s += "a"print("這是發生改變后的s, id為:", id(s)) # 這是發生改變后的s, id為: 139688067340160print(s)s = [] print("這是外部s, id為:", id(s)) # 這是外部s, id為: 139688067340160 # 執行結果 do_ls(s) # ["a"]?(3)注意點:函數中,默認參數只計算一次
def do_ls(l = [1]):l.append(1)print(l)do_ls() # [1,1] do_ls() # [1,1,1]python中異常處理:
try:# 無異常執行 except:# 發生異常執行 else:# 異常沒有發生,即執行 finally:# 無論是否發生異常都執行注意:可以研究raise庫,出現異常的時候,可以自帶自定義的錯誤信息
python中的GIL鎖:
(1)影響:
? ? ? ? a、同一時間只能有一個線程執行字節碼
? ? ? ? b、CPU密集計算,難用到多核優勢
? ? ? ? c、IO期間會釋放GIL,對IO密集程序影響不大
(2)避免GIL影響的方式:
? ? ? ? a、CPU密集可以使用多線程+進程池
? ? ? ? b、IO密集使用多線程/協程
? ? ? ? c、cython擴展
(3)有GIL鎖也要關注線程安全,因為非原子操作存在,在IO的時候,GIL鎖會釋放,其他線程開始執行,有可能會出現線程不安全
服務端性能優化措施:
(1)web應用一般語言不會成為瓶頸,數據結構與算法優化
(2)數據庫:索引優化、慢查詢消除、批量操作減少IO,NoSQL
(3)網絡IO:批量操作、pipeline操作減少IO
(4)緩存:內存數據庫redis、memcached
(5)異步:asyncio、celery
(6)并發:gevent、多線程
生成器與迭代器:
(1)生成器:
????????生成器本質上就是一個函數,它記住了上一次返回時在函數體中的位置。對生成器函數的第二次(或第n次)調用,跳轉到函數上一次掛起的位置。而且記錄了程序執行的上下文。生成器不僅“記住”了它的數據狀態,生成還記住了程序執行的位置。
(2)迭代器:
????????迭代器是一種支持next()操作的對象。它包含了一組元素,當執行next()操作時,返回其中一個元素。當所有元素都被返回后,再執行next()報異常—StopIteration生成器一定是可迭代的,也一定是迭代器對象
(3)區別:
????????a、生成器是生成元素的,迭代器是訪問集合元素的一中方式
????????b、迭代輸出生成器的內容
????????c、迭代器是一種支持next()操作的對象
????????d、迭代器(iterator):其中iterator對象表示的是一個數據流,可以把它看做一個有序序列,但我們不能提前知道序列的長度,只有通過nex()函數實現需要計算的下一個數據。可以看做生成器的一個子集。
python面向對象:
(1)創建一個對象的時候,會先調用__new__方法,再調用__init__進行初始化
(2)類變量:可以通過類或實例直接訪問的變量,可以修改
class Person:Country = 'China'def __init__(self, name):self.name = namedef print_name(self):print(self.name)wjf = Person("wjf") wjf.print_name() # wjf print(wjf.Country) # China print(Person.Country) # ChinaPerson.Country = "CHINA"print(wjf.Country) # CHINA print(Person.Country) # CHINA(3)classmethod和staticmethod的區別
? ? ? ? a、都可以class.method()的方式使用
? ? ? ? b、classmethod第一個參數是cls,可以引用類變量
? ? ? ? c、staticmethod用法和普通函數一樣,只是放到類里面組織
class Person:Country = 'China'def __init__(self, name):self.name = name@classmethoddef print_country(cls):print(cls.Country)@staticmethoddef join_name(first_name, last_name):print(first_name + last_name)Person.print_country() # China Person.join_name("vick", "·vi") # vick·vi(4)__call__函數:將對象變成函數的使用方式,例如:可用于用戶改變狀態的場景
class Person:def __call__(self,name):print("my name is ", name)wjf = Person() wjf("wjf") # my name is wjfpython裝飾器decorator:
(1)python中一切皆對象,函數也可以作為參數傳遞
(2)裝飾器是接受函數作為參數,添加功能后返回一個新函數的函數(類)
(3)@語法糖的方式使用裝飾器
(4)注意裝飾器的調用順序:裝飾順序,就近原則;執行順序,就遠原則;執行結束:就近原則。也可以理解為,就近入棧,執行時按出棧順序入棧,結束時按順序出棧,最終才結束函數調用。
def test1(func):print("test1被調用")def test1_1(*args, **kwargs):print("test1_1被調用")res = func(*args, **kwargs)print("test1_1被調用-end")return resreturn test1_1def test2(func):print("test2被調用")def test2_2(*args, **kwargs):print("test2_2被調用")res = func(*args, **kwargs)print("test2_2被調用-end")return resreturn test2_2@test1 @test2 def test():print("test被調用")return "結束"print(test())""" test2被調用 test1被調用 test1_1被調用 test2_2被調用 test被調用 test2_2被調用-end test1_1被調用-end 結束 """(5)帶參數的裝飾器
def test2(x):print("test2被調用")def test1(func):print("test1被調用")def test1_1(*args, **kwargs):print(x+1)res = func(*args, **kwargs)print("test1_1被調用-end")return resreturn test1_1return test1@test2(1) def test():print("test被調用")return "結束"print(test())""" test2被調用 test1被調用 2 test被調用 test1_1被調用-end 結束 """(6)類裝飾器
class test:def __init__(self, use_int=False) -> None:self.use_int = use_intdef __call__(self, func):def _log(*args, **kwargs):if self.use_int:print("打開")else:print("不打開")res = func(*args, **kwargs)return resreturn _log@test(True) def mydo():print("mydo執行了")return "結束"print(mydo())""" 打開 mydo執行了 結束 """python的設計模式:
(1)工廠模式:解決對象創建問題
(2)構造模式:控制復雜對象的創建(比如組裝電腦,這個模式允許自定義電腦的配置),創建和表示分離
(3)原型模式:通過原型的克隆創建新的實例
(4)單例模式:一個類只能創建同一個對象(容易被問到,甚至實現,比如說python的模塊)
class Singleton:def __new__(cls, *args, **kwargs):if not hasattr(cls, '_instance'):_instance = super().__new__(cls, *args, **kwargs)cls._instance = _instancereturn cls._instanceclass MyClass(Singleton):passc1 = MyClass() c2 = MyClass()print(c1 is c2) # true# is 和 == 的區別:is判斷引用是否一樣;==判斷值是否一樣(5)對象池模式:預先分配同一個類型的一組實例
(6)惰性計算模式:延遲計算(python的property)
多線程threading模塊:?
(1)threading.Thread類用來創建線程;
(2)start()方法啟動線程;
(3)可以用join()等待線程結束。
python多進程:
(1)multiprocessing多進程模塊;
(2)Multiprocessing.Process類實現多進程;
(3)一般在cpu密集程序里,可以使用,提高程序效率。
python的垃圾回收機制:
(1)引用計數為主(缺點:循環引用無法解決);
(2)引入標記清除和分代回收解決引用技術的問題。
數據結構
常用內置庫數據結構和算法:
(1) 線性結構:語言內置,list、tuple;內置庫:array、collections.namedtuple
(2)鏈式結構:內置庫,collections.deque(雙端隊列)
(3)字典結構:語言內置,dict;內置,collections.Counter(計數器)、collections.OrderedDict(有序字典)
(4)集合:語言內置,set、frozenset(不可變)
(5)排序算法:語言內置,sorted
(6)二分算法:內置庫,bisect
(7)堆算法:heapq模塊
collections模塊用法:
(1)Counter:字典的子類,提供了可哈希對象的計數功能
(2)defaultdict:字典的子類,提供了一個工廠函數,為字典查詢提供了默認值
(3)OrderedDict:字典的子類,保留了他們被添加的順序
(4)namedtuple:創建命名元組子類的工廠函數
(5)deque:類似列表容器,實現了在兩端快速添加(append)和彈出(pop)
dict底層使用的哈希表:
(1)為了支持快速查找,使用了哈希表作為底層
(2)哈希表平均查找時間復雜度O(1)
(3)使用二次探查法解決哈希沖突問題
其他部分有關算法會重新更新。
Linux操作系統
日常開發用到命令:
根據進程名查看進程號:ps -ef | grep 進程名
根據進程號查看占用的端口:netstat -apn | grep 進程號 -m 顯示多少條
根據端口號查看使用的進程:lsof -i:端口號
實時抓取某個文件的內容:tail -f 文件名
Ubuntu的定時任務:crontab -l:顯示定時任務有哪些;crontab -e進入編輯
window下需要用到命令:
查看所有進程占用的端口:?netstat -ano
查看占用指定端口的進程信息:netstat -aon|findstr "8000"
根據進程號查看進程信息:?tasklist|findstr "10076"
結束進程:taskkill /T /F /PID 10076
進程與線程的區別:
(1) 進程是對運行時程序的封裝,是系統資源調度和分配的基本單位;
(2)線程是進程的子任務,cpu調度和分配的基本單位,實現進程內的并發;
(3)一個進程可以包含多個線程,線程依賴進程存在,并共享進程內存。
線程同步的方式:
(1)互斥量(鎖):通過互斥機制防止多個線程同時訪問公共資源;
(2)信號量:控制同一時刻多個線程訪問同一個資源的線程數;
(3)事件(信號):通過通知的方式保持多個線程同步。
進程間通信的方式:
(1)管道/匿名管道/有名管道(pipe)
(2)信號:比如用戶使用ctrl+c產生SIGINT程序終止信號;
(3)消息隊列(Message);
(4)共享內存;
(5)信號量;
(6)套接字(socket):最常用的方式,我們的web應用都是這種方式。
分頁機制:邏輯地址和物理地址分離的內存分配管理方案
(1)程序的邏輯地址劃分為固定大小的頁;
(2)物理地址劃分為同樣大小的幀;
(3)通過頁表對應邏輯地址和物理地址;
分段機制:為了滿足代碼的一些邏輯需求
(1)數據共享,數據保護,動態鏈接等;
(2)通過段表實現邏輯地址和物理地址的映射;
(3)每個段內部是連續內存分配,段和段之間是離散分配的
分段和分頁的區別:
(1) 頁是出于內存利用率的角度提出的離散分配機制;
(2)段是出于用戶角度,用于數據保護、數據隔離等用途的管理機制;
(3)頁的大小是固定的,操作系統決定的;段大小不確定,用戶程序決定。
虛擬內存:把一些暫時不用的內存信息放到硬盤上
(1)局部性原理,程序運行時只有部分必要的信息裝入內存;
(2)內存中暫時不需要的內容放到硬盤上;
(3)系統好像提供了比實際內存大得多的容量,為虛擬內存。
內存抖動:
(1)頻繁的頁調度,進程不斷產生缺頁中段;
(2)置換一個頁,又不斷再次需要這個頁;
(3)運行程序太多;頁面替換策略不好;
(4)解決方案,終止進程或者增加物理內存。
死鎖:一組進程中,每個進程都無限等待被該組進程中另一進程所占有的資源,因而永遠無法得到的資源,這種現象稱為進程死鎖,這一組進程就稱為死鎖進程
(1)互斥使用(資源獨占):一個資源每次只能給一個進程使用;
(2)占有且等待(請求和保持,部分分配):進程在申請新的資源的同時保持對原有資源的占有;
(3)不可搶占(不可剝奪):資源申請者不能強行的從資源占有者手中奪取資源,資源只能由占有者自愿釋放;
(4)循環等待:存在一個進程等待隊列 {P1 , P2 , … , Pn},其中P1等待P2占有的資源,P2等待P3占有的資源,…,Pn等待P1占有的資源,形成一個進程等待環路。
當死鎖產生的時候一定會有這四個條件,有一個條件不成立都不會造成死鎖。
計算機網絡
瀏覽器輸入一個url中間經歷的過程:
(1)DNS查詢(域名解析)
(2)TCP握手(3次握手)
(3)HTTP請求
(4)反向代理Nginx(負載均衡)
(5)uwsgi/gunicom
(6)web app響應
(7)TCP揮手(4次揮手)
TCP 和 UDP的區別:
(1)tcp,面向連接、可靠的、基于字節流
(2)無連接、不可靠、面向報文
5中IO模型:
(1)Blocking IO(阻塞io)
(2)Nonblocking IO(非阻塞io)
(3)IO multiplexing(io多路復用)
(4)Signal Driven IO(信號驅動io)
(5)Asynchronous IO(異步io)
io多路復用:
(1)為了實現高并發需要一種機制并發處理多個socket
(2)Linux常見的是select/poll/epoll
(3)可以使用單線程單進程處理多個socket
三握四揮:
(1)TCP/IP 協議是傳輸層的一個面向連接的安全可靠的一個傳輸協議,三次握手的機制是為了保證能建立一個安全可靠的連接,那么第一次握手是由客戶端發起,客戶端會向服務端發送一個報文,在報文里面:SYN標志位置為1,表示發起新的連接。當服務端收到這個報文之后就知道客戶端要和我建立一個新的連接,于是服務端就向客戶端發送一個確認消息包,在這個消息包里面:ack標志位置為1,表示確認客戶端發起的第一次連接請求。以上兩次握手之后,對于客戶端而言:已經明確了我既能給服務端成功發消息,也能成功收到服務端的響應。但是對于服務端而言:兩次握手是不夠的,因為到目前為止,服務端只知道一件事,客戶端發給我的消息我能收到,但是我響應給客戶端的消息,客戶端能不能收到我是不知道的。所以,還需要進行第三次握手,第三次握手就是當客戶端收到服務端發送的確認響應報文之后,還要繼續去給服務端進行回應,也是一個ack標志位置1的確認消息。通過以上三次連接,不管是客戶端還是服務端,都知道我既能給對方發送消息,也能收到對方的響應。那么,這個連接就被安全的建了。
?
(2)四次握手機制也是由客戶端去發起,客戶端會發送一個報文,在報文里面FIN位標志位置一,當服務端收到這個報文之后,我就知道了客戶端想要和我斷開連接,但是此時服務端不一定能做好準備,因為當客戶端發起斷開連接的這個消息的時候,對于服務端而言,他和還有可能有未發送完的消息,他還要繼續發送,所以呢,此時對于服務端而言,我只能進行一個消息確認,就是我先告訴服務端,我知道你要給我斷開連接了,但是我這里邊還可能沒有做好準備,你需要等我一下,等會兒我會告訴你,于是呢,發完這個消息確認包之后,可能稍過片刻它就會繼續發送一個斷開連接的一個報文啊,也是一個FIN位置1的報文也是由服務端發給客戶端的啊,這個報文表示服務端已經做好了斷開連接的準備,那么當這個報文發給客戶端的時候,客戶端同樣要給服務端繼續發送一個消息確認的報文一共有四次,那么,通過這四次的相互溝通和連接,我就知道了,不管是服務端還是客戶端都已經做好了斷開連接的
https加密過程
①https加密過程,為了防止中間人攻擊,所以先使用非對稱加密,產生了會話密鑰后,再使用會話密鑰進行對稱加密進行消息的傳輸。
②非對稱加密,就是服務端發送公鑰s給客戶端后,客戶端使用公鑰s加密了數據后,再發送給服務端,服務端可以使用私鑰進行解密。
mysql數據庫
事務是什么:
(1)事務是數據庫并發控制的基本單位;
(2)事務1可以看作是一系列sql語句的集合;
(3)事務必須要么全部執行成功,要么全部執行失敗(回滾);
事務的4個特性ACID:
(1)原子性:一個事務中所有操作全部完成或失敗;
(2)一致性:事務開始和結束之后數據完整新沒被破壞;
(3)隔離性:允許多個事務同時對數據庫修改和讀寫;
(4)持久性:事務結束之后,修改是永遠的不會丟失。
事務并發會出現4種問題:
(1)幻讀:一個事務第二次查出現第一次沒有的結果;
(2)非重復讀:一個事務重復讀兩次得到不同結果(獲得結果不是最新的);
(3)臟讀:一個事務讀取到另一個事務沒有提交的修改;
(4)丟失修改:并發寫入造成其中一些修改丟失。
事務的4種隔離級別:
(1)讀未提交:別的事務讀到未提交的數據;
(2)讀已提交:只能讀取已經提交的數據;
(3)可重復讀:同一個事務先后查詢結果一頁(默認);
(4)串行讀:事務完成串行化的執行,隔離級別最高,執行效率最低。
防止高并發下插入重復值:
(1)使用數據庫的唯一索引;
(2)使用隊列異步寫入;
(3)使用redis實現分布式鎖;
樂觀鎖和悲觀鎖:
(1)悲觀鎖,先獲取鎖再進行操作。一鎖二查三更新;
(2)樂觀鎖,先修改,更新的時候發現數據變了就回滾。
InnoDB和MyISAM引擎的區別:
(1)MyISAM不支持事務,InnoDB支持事務;
(2)MyISAM不支持外鍵,InnoDB支持外鍵;
(3)MyISAM只支持表鎖,InnoDB支持行鎖和表鎖;
B-Tree:
(1)多路平衡查找樹(每個節點最多m(m>=2)個孩子,稱為m階或者度);
(2)葉節點具有相同的深度;
(3)節點中的數據key從左到右是遞增的。
B+Tree:
(1)mysql實際使用的B+Tree作為索引的數據結構;
(2)只在葉子節點帶有指向記錄的指針(可以增加樹的度);
(3)葉子節點通過指針相連(實現范圍查詢)。
mysql索引的類型:
(1)普通索引(create index);
(2)唯一索引,索引列的值必須是唯一的(create unique index);
(3)多列索引;
(4)主鍵索引(primary key),一個表只能有一個;
(5)全文索引(fulltext index),InnDB不支持。
什么時候創建索引:
(1)經常用作查詢條件的字段(where條件);
(2)經常用作表連接的字段;
(3)經常出現在order by,group by 之后的字段。
哪些字段適合當索引:
(1)非空字段;
(2)區分度高,離散度大,作為索引的字段值盡量不要有大量相同值;
(3)索引的長度不要太長(比較耗費時間);
索引失效:口訣:模糊匹配、類型隱轉、最左匹配
(1)以%開頭的like語句,模糊搜索;
(2)出現隱式類型轉換(在python這種動態語言查詢中需要注意);
(3)沒有滿足最左匹配原則;
比如:a, b, c為聯合索引如果: where a b c; where a b; where a; where b c; 這個會導致索引失效?聚集索引和非聚集索引:
(1)聚集和非聚集:是B+Tree葉節點存的是指針還是數據記錄;
(2)MyISAM索引和數據分離,使用的非聚集;
(3)InnoDB數據文件就是索引文件,主鍵索引就是聚集索引。
用該兩表來探究mysql連接的區別
內連接:
?(1)將左表和右表關聯起來的數據連接后返回;
(2)類似求兩個表的交集
(3)select * from A inner join B on A.id=B.id;
?外連接:
(1)左連接返回左表中所有記錄,即使右表中沒有匹配的記錄(left join);
(2)右連接返回右表中所有記錄,即使左表中沒有匹配的記錄(right join)
mysql分區:
(1)概念:分區就是把一張表分成N多個區塊。分區表是一個獨立的邏輯表,但是底層由多個物理子表組成。當查詢條件的數據分布在某一個分區的時候,查詢引擎只會去某一個分區查詢,而不是遍歷整個表。如果需要刪除某一個分區的數據,只需要刪除對應的分區即可。
(2)分區表的類型:
????????①range分區:按照范圍分區。比如按照時間范圍分區。
????????②list分區:和range分區相似,主要區別在于list是枚舉值列表的集合,range是連續的區間值的集合。對于list分區,分區字段必須是已知的,如果插入的字段不在分區時的枚舉值中,將無法插入。
? ? ? ? ③hash分區:可以將數據均勻地分布到預先定義的分區中。
(3)分區可能出現的問題:
????????①打開和鎖住所有底層表的成本可能很高。當查詢訪問分區表時,mysql需要打開并鎖住所有的底層表,這個操作在分區過濾前發生,所以無法通過分區過濾來降低此開銷,會影響到查詢速度,可以通過批量操作來降低此類開銷,比如批量插入、LOAD DATA INFILE和一次刪除多條數據。
????????②維護分區的成本可能很高,例如重組分區,會先創建一個臨時分區,然后將數據復制到其中,最后再刪除原分區。
????????③所有分區必須使用相同的存儲引擎。
緩存redis:內存數據庫
redis的作用:
(1)緩解關系數據庫(常見的是mysql)并發訪問的壓力:熱點數據;
(2)減少響應時間:內存IO速度比磁盤快;
(3)提升吞吐量:redis等內存數據庫單機就可以支撐很大的并發;
(4)redis和memcached主要區別,就是redis可以持久化。
redis的數據類型:
(1)String(字符串):用來實現簡單的kv鍵值對存儲,比如計數器;
(2)List(鏈表):實現雙向鏈表,比如用戶關注,粉絲列表;
(3)hash(哈希表):用來存儲彼此相關的鍵值對;
(4)set(集合):存儲不重復元素,比如用戶的關注者;
(5)sorted set(有序集合):實時信息排行榜
web知識點
什么是WSGI:
(1)解決python web server亂象;
(2)描述了web server(Gunicorn/uWSGI)如何與web框架(Flask/Django)交互,web框架如何處理請求;
web框架對比:
(1)Djingo:大而全,內置ORM、Admin等組件,第三方插件比較多;
(2)Flask:微框架,插件機制,比較靈活;
(3)Tornado:異步支持的微框架和異步網絡庫。
MVC是什么:
(1)Model:負責業務對象和數據庫的交互(ORM)
(2)View:負責與用戶的交互展示;
(3)Controller:接收請求參數調用模型和視圖完成請求。
常見的web安全問題:
(1)sql注入;
(2)xss(跨站腳本攻擊);
(3)csrf(跨站請求偽造)。
sql注入:
(1)通過構造特殊的輸入參數傳入web應用,導致后端執行了惡意sql;
(2)通常由于程序員未對輸入進行過濾,直接動態拼接sql產生;
(3)可以使用開源工具sqlmap、sqlninja檢測。
如何防范sql注入:永遠不要相信用戶的任何輸入
(1)對輸入參數做好檢查(類型和范圍);過濾和轉義特殊字符;
(2)不要直接拼接使用sql,使用ORM可以大大降低sql注入風險;
(3)數據庫層:做好權限管理配置;不要明文存敏感信息。
xss攻擊:
(1)惡意用戶將代碼植入到提供給其他用戶使用的頁面中,未經轉義的惡意代碼輸出到其他用戶的瀏覽器被執行;
(2)用戶瀏覽頁面的時候嵌入頁面的腳本(js)會被執行,攻擊用戶;
(3)主要分未為:反射型(非持久型)、存儲型(持久型)。
前后端分離是什么:
后端只負責提供數據接口,不再渲染模板,前端獲取數據并呈現
前后端分離的優點:
(1)前后端解耦,接口復用(前端和客戶端共用接口),減少并發量;
(2)各司其職,前后端同步開發,提升工作效率,定義號接口規范;
(3)更有利于調試(mock),測試和運維部署。
通俗易懂的RESTful:
本質上設計出來是為了解決url膨脹的問題,因為曾經的url,一個url對應一個操作、狀態等,后續會出現過多的url難以管理,所以出現了restful風格。通過在representation增加更多的描述,然后后端再根據描述返回對應的結果。所以restful風格沒有解決前后端的工作量,只是解決了url膨脹的問題。
什么是RESTful:
(1)表現層狀態轉移,由于http協議的主要設計者提出;
(2)資源(resources),表現層(representation),狀態轉化(state transfer)
(3)是一種以資源為中心的web軟件架構風格,可以用Ajax和RESTful web服務構建應用;
(4)Resources(資源):使用URI指向的一個實體;
(5)Representation(表現層):資源的表現形式,比如圖片、html文本;
(6)State Transfer(狀態轉化):get、post、put、delete http動詞來操作資源,實現資源狀態的改變。
RESTful的準則:?
(1)所有事物抽象為資源(resource),資源對應唯一的標識(identifier);
(2)資源通過接口進行操作實現狀態轉移,操作本身是無狀態的;
(3)對資源的操作不會改變資源的標識。
RESTful API:
(1)通過http get、post、put、delete 獲取、新建、更新、刪除 資源;
(2)一般使用json格式返回數據;
(3)一般web框架都有相應的插件支持RESTfu API。
python 運行后無法停止,查端口的方式linux (1)ps -ef | grep python (2)ps aux | grep python window (1)wmic process where name="python.exe" list fullsession、cookie、token:
共同點:都是用于鑒權、記錄用戶信息、保持用戶操作
區別:
(1)session:存于服務端,記錄用戶信息,客戶端只存sessionId,缺點大量用戶需要session的時候,增加服務器的存儲成本
(2)cookie:存于客戶端,記錄用戶信息,缺點較為不安全?
(3)token:基于jwt,記錄用戶信息,客戶端存token,服務端只存token的密鑰
nginx分包方式(負載均衡):?
php?
操作數據庫分頁
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <?phpclass MysqlConn {public $host, $port, $user, $passwd, $db;public $conn;function __construct($host, $port, $user, $passwd, $db){$this->host = $host;$this->port = $port;$this->user = $user;$this->passwd = $passwd;$this->db = $db;$this->conn = $this->getConn();}private function getConn() {$conn = new mysqli($this->host,$this->user, $this->passwd, $this->db, $this->port);if ($conn->connect_error) {throw new Exception($conn->connect_error);}return $conn;}function readRow($offset, $limit, $table, $where) {$sql = "select * from $table ";if (count($where) != 0) {$sql .= "where ";$lenNum = count($where);foreach ($where as $k=>$value) {$lenNum -= 1;if ($lenNum < 1) {$sql .= "$k = $value ";} else {$sql .= "$k = $value and ";}}}if ($limit != 0) {$sql .= "limit $limit ";}if ($offset != 0) {$sql .= "offset $offset";}echo $sql;$res = $this->conn->query($sql);if ($res) {while ($arr = $res->fetch_assoc()) {echo "<br>";echo var_dump($arr);}} else {echo "no row";}}function __destruct() {$this->conn->close();} } try {$conn = new MysqlConn("127.0.0.1", 3306, "root", "123456", "reward");echo "連接成功";$where = [// "id"=>19];$table = "users";$offset = 5;$limit = 5;$conn->readRow($offset, $limit, $table, $where); } catch (Exception $e) {echo $e->getMessage(); }?通用分頁類:
<?phpClass FY {public $maxNum;function __construct($num) {$this->maxNum = $num;}function getPageNum() {$pageNum = $_GET["pagenum"];return $pageNum;}function getData($pageNum) {$preNum = $pageNum-1;$preStr = "<a href='http://localhost:8080/php_stu/fy/fengye.php?pagenum=$preNum&&maxpage=$this->maxNum'><<< pre</a>";$preStrGrep = "<a style='color:gray;'><<< pre</a>";$nextNum = $pageNum+1;$nextStr = "<a href='http://localhost:8080/php_stu/fy/fengye.php?pagenum=$nextNum&&maxpage=$this->maxNum'>next >>></a>";$nextStrGrep = "<a style='color:gray;'>next >>></a>";// 小于等于0if ($this->maxNum <= 0) {echo $preStrGrep . " " . $nextStrGrep;return;}$temA = "<a href='http://localhost:8080/php_stu/fy/fengye.php?pagenum=%s&&maxpage=$this->maxNum'>  %s  </a>";$temB = "<b>  %s  </b>";// [1,10]if ($this->maxNum <= 10) {$endStr = "";if ($pageNum == 1) {$endStr .= $preStrGrep;} else {$endStr .= $preStr;}for ($i=1; $i<=$this->maxNum;$i++) {if ($i == $pageNum) {$tempStr = sprintf($temB, $i);$endStr .= $tempStr;} else {$tempStr = sprintf($temA, $i, $i);$endStr .= $tempStr;}}if ($pageNum == $this->maxNum) {$endStr .= $nextStrGrep;} else {$endStr .= $nextStr;}echo $endStr;return;}// (10, +無窮)if ($this->maxNum > 10) {$endStr = "";if ($pageNum == 1) {$endStr .= $preStrGrep;} else {$endStr .= $preStr;}$startNum = 0; $endNum = 0;// 找起始, 加前綴if ($pageNum < 10) {$startNum = 1; $endNum = 10;} elseif ($pageNum >= 10 and $pageNum <= $this->maxNum-10) {$startNum = $pageNum -5;$endNum = $pageNum + 5;$endStr .= sprintf($temA, 1, 1);$endStr .= sprintf($temA, 2, 2);$endStr .= " ... ";} elseif ($pageNum > $this->maxNum-10) {$startNum = $this->maxNum-10;$endNum = $this->maxNum;$endStr .= sprintf($temA, 1, 1);$endStr .= sprintf($temA, 2, 2);$endStr .= " ... ";}for ($i=$startNum; $i<=$endNum;$i++) {if ($i == $pageNum) {$tempStr = sprintf($temB, $i);$endStr .= $tempStr;} else {$tempStr = sprintf($temA, $i, $i);$endStr .= $tempStr;}}// 加后綴if ($pageNum < 10) {$endStr .= " ... ";$endStr .= sprintf($temA, $this->maxNum-1, $this->maxNum-1);$endStr .= sprintf($temA, $this->maxNum, $this->maxNum);} elseif ($pageNum >= 10 and $pageNum <= $this->maxNum-10) {$endStr .= " ... ";$endStr .= sprintf($temA, $this->maxNum-1, $this->maxNum-1);$endStr .= sprintf($temA, $this->maxNum, $this->maxNum);} elseif ($pageNum > $this->maxNum-10) {// $endStr .= " ... ";}if ($pageNum == $this->maxNum) {$endStr .= $nextStrGrep;} else {$endStr .= $nextStr;}echo $endStr;return;}} }function getMaxPage() {$maxPage = $_GET["maxpage"];return $maxPage; }$maxPage = getMaxPage();$obj = new FY($maxPage); $pageNum = $obj->getPageNum(); $obj->getData($pageNum);?效果如上
總結
以上是生活随笔為你收集整理的python后端知识点的自我复习的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于ThinkPhp6+Vue+Elem
- 下一篇: python数据集划分_机器学习和数据集