劍指offer-python面試篇第一部分

互聯網協議定義(分別有4層、5層及7層協議的說法,如下從上層向下層介紹)?

a) 四層協議應用層傳輸層網絡層網絡接口層python

a) 五層協議:mysql

應用層:用戶使用的應用程序都歸屬於應用層,做用爲規定應用程序的數據格式。web

傳輸層:網絡層幫咱們找到主機,可是區分應用層的應用就是靠端口,因此傳輸層就是創建端口到端口的通訊。(端口範圍0-655350-1023爲系統佔用端口ajax

網絡層:區分不一樣的廣播域或者子網(不然發送一條數據全世界都會受到,是災難)。正則表達式

數據鏈路層:定義電信號的分組方式。redis

物理層:基於電器特性發送高低點電壓(電信號),高電壓對應數字1,低電壓對應數字0sql

C)七層協議:(應用層、表示層、會話層)、傳輸層、網絡層、(數據鏈路層、物理層)mongodb

傳輸層基於tcp協議的三次握手和四次揮手?

傳輸層有兩種數據傳輸協議分別爲TCP協議和UDP協議,其中TCP協議爲可靠傳輸,數據包沒有長度設置,理論能夠無限長,而UDP協議爲不可靠傳輸,報頭一共就8個字節。Tcp的三次握手和四次揮手定義爲創建鏈接時三次握手完成創建鏈接而後傳輸數據斷開鏈接時是四次揮手因此tcp傳輸數據是安全的數據庫

爲何鏈接的時候是三次握手,關閉的時候倒是四次揮手?

由於當Server端收到Client端的SYN鏈接請求報文後,能夠直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。可是關閉鏈接時,當Server端收到FIN報文時,極可能並不會當即關閉SOCKET,因此只能先回復一個ACK報文,告訴Client端,"你發的FIN報文我收到了"。只有等到我Server端全部的報文都發送完了,我才能發送FIN報文,所以不能一塊兒發送。故須要四步握手。django

什麼是socket?

socket是在應用層和傳輸層之間的一個抽象層,它把TCP/IP層複雜的操做抽象爲幾個簡單的接口供應用層調用以實現進程在網絡中通訊。

什麼是多路複用和多路複用要解決的問題?

多道技術的實現就是爲了解決多個程序競爭或者共享同一個資源(好比cpu)的有序調度問題,解決方式便是多路複用。多路複用分爲時間上的複用和空間上的複用,空間上的多路複用是指將內存分爲幾部分,每一部分放一個程序,這樣同一時間內存中就有多道程序,前提保證內存是分割;時間上的多路複用是指多個程序須要在一個cpu上運行,不一樣的程序輪流使用cpu,當某個程序運行的時間過長或者遇到I/O阻塞,操做系統會把cpu分配給下一個程序,保證cpu處於高使用率,實現僞併發。

併發與並行的區別?

併發不是並行,但看起來像是同時運行的單個cpu和多道技術就能夠實現併發並行也屬於併發指的是同時運行只有具有多個cpu才能實現並行

進程、線程、協程的定義?

進程是具備必定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位。每一個進程都有本身的獨立內存空間,不一樣進程經過進程間通訊來通訊。因爲進程比較重量,佔據獨立的內存,因此上下文進程間的切換開銷(棧、寄存器、虛擬內存、文件句柄等)比較大,但相對比較穩定安全。

線程是進程的一個實體,CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位.線程本身基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),可是它可與同屬一個進程的其餘的線程共享進程所擁有的所有資源。線程間通訊主要經過共享內存,上下文切換很快,資源開銷較少,但相比進程不夠穩定容易丟失數據。

協程是一種用戶態的輕量級線程,協程的調度徹底由用戶控制。協程擁有本身的寄存器上下文和棧。協程調度切換時,將寄存器上下文和棧保存到其餘地方,在切回來的時候,恢復先前保存的寄存器上下文和棧,直接操做棧則基本沒有內核切換的開銷,能夠不加鎖的訪問全局變量,因此上下文的切換很是快。

進程、線程、協程的區別?

線程是指進程內的一個執行單元,也是進程內的可調度實體。線程與進程的區別:
1) 地址空間:線程是進程內的一個執行單元,進程內至少有一個線程,它們共享進程的地址空間,而進程有本身獨立的地址空間
2) 資源擁有:進程是資源分配和擁有的單位,同一個進程內的線程共享進程的資源
3) 線程是處理器調度的基本單位,但進程不是
4) 兩者都可併發執行

5) 每一個獨立的線程有一個程序運行的入口、順序執行序列和程序的出口,可是線程不可以獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制

協程多與線程進行比較:

1) 一個線程能夠多個協程,一個進程也能夠單獨擁有多個協程,這樣python中則能使用多核CPU

2) 線程進程都是同步機制,而協程則是異步

3) 協程能保留上一次調用時的狀態,每次過程重入時,就至關於進入上一次調用的狀態

進程同步鎖概念介紹

程之間數據不共享可是共享同一套文件系統因此訪問同一個文件或者打印終端是能夠的共享帶來了競爭競爭的結果就是混亂解決辦法就是加鎖處理加鎖能夠保證多個進程修改同一塊數據時,同一時間只能有一個任務能夠進行修改,即串行的修改,沒錯,速度是慢了,但犧牲了速度卻保證了數據安全。

生產者消費者模型?

程序中有兩類角色一類負責生產數據(生產者)一類負責處理數據(消費者)引入生產者消費者模型爲了解決的問題是:平衡生產者與消費者之間的工做能力,從而提升程序總體處理數據的速度如何實現:生產者<-->隊列<——>消費者生產者消費者模型實現類程序的解耦和

進程與線程的關係?

進程如一個車間線程如車間內的一條流水線;建立進程須要申請特別的內存空間(車間),各進程間是競爭關係,因此建立進程的開銷大;而多個線程屬於同一個進程(車間),線程間共享進程中的資源,屬於合做關係,因此建立線程開銷小。因此,進程只是用來把資源集中到一塊兒(進程只是一個資源單位,或者說資源集合),而線程纔是cpu上的執行單位。

什麼是協程?

協程是單線程下的併發本質就是在單線程下,由用戶本身控制一個任務遇到io阻塞了就切換另一個任務去執行,以此來提高效率。

優勢協程的切換開銷更小,屬於程序級別的切換,操做系統徹底感知不到,於是更加輕量級單線程內就能夠實現併發的效果,最大限度地利用cpu

缺點協程的本質是單線程下,沒法利用多核,能夠是一個程序開啓多個進程,每一個進程內開啓多個線程,每一個線程內開啓協程協程指的是單個線程,於是一旦協程出現阻塞,將會阻塞整個線程

 

數據庫分類

關係型數據庫sqllitedb2oracleaccesssql serverMySQL,注意:sql語句通用須要有表結構非關係型:mongodbredismemcache非關係型數據庫是key-value存儲的,沒有表結構

MyISAMInnoDB搜索引擎的特色

存儲引擎說白了就是如何存儲數據、如何爲存儲的數據創建索引和如何更新、查詢數據等技術的實現方法。因此存儲引擎也能夠稱爲表類型。

MyISAM
    特色:
    1)不支持事務:MyISAM存儲引擎不支持事務,因此對事務有要求的業務場景不能使用
    2)表級鎖定:其鎖定機制是表級索引,這雖然可讓鎖定的實現成本很小可是也同時大大下降了其併發性能
    3)讀寫互相阻塞:不只會在寫入的時候阻塞讀取,MyISAM還會在讀取的時候阻塞寫入,但讀自己並不會阻塞另外的讀
    4)只會緩存索引:MyISAM能夠經過key_buffer緩存以大大提升訪問性能減小磁盤IO,可是這個緩存區只會緩存索引,而不會緩存數據
    適用場景:
    1)不須要事務支持(不支持)
    2)併發相對較低(鎖定機制問題)
    3)數據修改相對較少(阻塞問題)
    4)以讀爲主
    5)數據一致性要求不是很是高
InnoDB
    特色:
    1)具備較好的事務支持:支持4個事務隔離級別,支持多版本讀
    2)行級鎖定:經過索引實現,全表掃描仍然會是表鎖,注意間隙鎖的影響
    3)讀寫阻塞與事務隔離級別相關
    4)具備很是高效的緩存特性:能緩存索引,也能緩存數據
    5)整個表和主鍵以Cluster方式存儲,組成一顆平衡樹
    6)全部Secondary Index都會保存主鍵信息
    適用場景:
    1)須要事務支持(具備較好的事務特性)
    2)行級鎖定對高併發有很好的適應能力,但須要確保查詢是經過索引完成
    3)數據更新較爲頻繁的場景
    4)數據一致性要求較高
    5)硬件設備內存較大,能夠利用InnoDB較好的緩存能力來提升內存利用率,儘量減小磁盤 IO

 

char varchar字符串類型的區別

char類型:定長存入字符長度大於設置長度時報錯,存入字符長度小於設置長度時,會用空格填充,達到設置字符長度,簡單粗暴,浪費空間,存取速度快

Varchar類型:varchar類型存儲數據的真實內容,不會用空格填充會在真實數據前加1-2Bytes的前綴,該前綴用來表示真實數據的bytes字節數變長,精準,節省空間,存取速度慢

雖然varchar使用起來較爲靈活,可是從整個系統的性能角度來講,char數據類型的處理速度更快,有時甚至能夠超出varchar處理速度的50%。所以,用戶在設計數據庫時應當綜合考慮各方面的因素,以求達到最佳的平衡

 

 

foreign key外鍵關聯(一對多)實例。

create table press(

id int primary key auto_increment,

name varchar(20)

);

create table book(

id int primary key auto_increment,

name varchar(20),

press_id int not null,

foreign key(press_id) references press(id)

on delete cascade

on update cascade

);

mysql索引相關介紹。

 

索引分單列索引和組合索引。單列索引,即一個索引只包含單個列,一個表能夠有多個單列索引,但這不是組合索引。組合索引,即一個索引包含多個列。MySQL索引的創建對於MySQL的高效運行是很重要的,索引能夠大大提升MySQL的檢索速度。實際上,索引也是一張表,該表保存了主鍵與索引字段,並指向實體表的記錄。

 

上面都在說使用索引的好處,但過多的使用索引將會形成濫用。所以索引也會有它的缺點:雖然索引大大提升了查詢速度,同時卻會下降更新表的速度,如對錶進行INSERTUPDATEDELETE。由於更新表時,MySQL不只要保存數據,還要保存一下索引文件。創建索引會佔用磁盤空間的索引文件。

 

聯合索引命中規則是最左匹配規則以下聯合索引(姓名,年齡,性別):

諸如select * from user where name= ‘zzz’ and sex=’male’ and age=18查詢語句當對name、sex、age分別創建列索引和創建namesex、age)組合索引時,查詢的結果是不同的,組合索引效率高於多個列索引,由於在執行多個列索引的時候,mysql只會選擇其中一個效率最高的。可是經過組合索引就直接鎖定那一條信息了。因爲組合索引的最左匹配原則,上述組合索引至關於分別創建(name),(namesex,namesexage)這樣的三個索引,只有查詢條件與這三個順序相一致的纔會用到組合索引。

 

MySQL在如下操做場景下會使用索引

 

1) 快速查找符合where條件的記錄
2) 快速肯定候選集。where條件使用了多個索引字段,則MySQL會優先使用能使候選記錄集規模最小的那個索引,以便儘快淘汰不符合條件的記錄。
3) 若是表中存在幾個字段構成的聯合索引,則查找記錄時,這個聯合索引的最左前綴匹配字段也會被自動做爲索引來加速查找。
例如,若爲某表建立了3個字段(c1, c2, c3)構成的聯合索引,則(c1), (c1, c2), (c1, c2, c3)均會做爲索引,(c2, c3)就不會被做爲索引,而(c1, c3)其實只利用到c1索引。
4) 多表作join操做時會使用索引(若是參與join的字段在這些表中均創建了索引的話)。
5) 若某字段已創建索引,求該字段的min()max()時,MySQL會使用索引。
6) 對創建了索引的字段作sortgroup操做時,MySQL會使用索引。

 

redis如何作持久化?

 

由於Redis是內存型數據庫,因此爲了防止由於系統崩潰等緣由致使數據丟失的問題,Redis提供了兩種不一樣的持久化方法來將數據存儲在硬盤裏面,一種方法是快照(RDB),它能夠將存在於某一個時刻的全部數據都寫入到硬盤裏面,另一種方法是隻追加文件(AOF),它會在執行寫命令時,將被執行的寫命令都寫入到硬盤裏面。

 

快照持久化Redis能夠經過建立快照來得到在內存裏面的數據在某一個時間點上的副本。在建立快照以後,用戶能夠對快照進行備份,能夠將快照複製到其它服務器從而建立具備相同數據的服務器副本,還能夠將快照留在原地以便重啓服務器時使用。在只使用快照持久化來保存數據時,若是系統真的發生崩潰,用戶將丟失最近一次生成快照以後更改的全部數據。所以,快照持久化只適用於那些即便丟失一部分數據也不會形成問題的應用程序。有兩個命令能夠用於生成RDB文件,一個是SAVE,另一個BGSAVE

 

SAVE特色:SAVE命令會阻塞Redis服務器進程,直到RDB文件建立完畢,在服務器進程阻塞期間,服務器不能處理任何命令請求。缺點:服務器持久化期間沒法接受其它請求。

 

BGSAVE特色:BGSAVE命令則會派生出一個子進程,而後由子進程負責建立RDB文件,服務器進程則繼續處理命令請求。缺點:建立子進程所耗費的時間會隨着Redis佔用的內存而增長。

 

文件持久化AOF持久化會將被執行的寫命令寫到AOF文件的末尾,以此來紀錄數據所發生的變化,所以,Redis只要從頭至尾從新執行一次AOF文件所包含的全部寫命令,就能夠恢復AOF文件所記錄的數據集。由於Redis會不斷的將被執行的寫命令紀錄到AOF文件裏面,因此隨着Redis不斷執行,AOF文件的體積也會不斷增加,極端條件下,AOF甚至可能會用完硬盤的全部可用空間。爲了解決上面的缺點,Redis提供了BGREWRITEAOF命令,這個命令會經過移除AOF文件中的冗餘命令來重寫AOF文件,使得AOF文件儘量的小。它的原理和BGSAVE命令類似,Redis會建立一個子進程,而後由子進程負責對AOF文件進行重寫,由於AOF文件重寫也須要用到子進程,因此一樣存在快照持久化由於建立子進程所致使的性能問題和內存佔用問題。

 

djangohttp請求流程

 

http協議與https協議的區別?

 

HTTP:是互聯網上應用最爲普遍的一種網絡協議,是一個客戶端和服務器端請求和應答的標準(TCP),用於從WWW服務器傳輸超文本到本地瀏覽器的傳輸協議,它可使瀏覽器更加高效,使網絡傳輸減小。

 

HTTPS:是以安全爲目標的HTTP通道,簡單講是HTTP的安全版,即HTTP下加入SSL層,HTTPS的安全基礎是SSL,所以加密的詳細內容就須要SSL做用有一種是創建一個信息安全通道,來保證數據傳輸的安全;另外一種就是確認網站的真實性。

 

1https協議須要到ca申請證書,通常免費證書較少,於是須要必定費用。

 

2http是超文本傳輸協議,信息是明文傳輸,https則是具備安全性的ssl加密傳輸協議。

 

3httphttps使用的是徹底不一樣的鏈接方式,用的端口也不同,前者是80,後者是443

 

4http的鏈接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。

 

websocket協議?

 

http協議:HTTP 協議是一種無狀態的、無鏈接的、單向的應用層協議。它採用了請求/響應模型。通訊請求只能由客戶端發起,服務端對請求作出應答處理。HTTP 協議沒法實現服務器主動向客戶端發起消息

 

Websocket協議:WebSocket 鏈接容許客戶端和服務器之間進行全雙工通訊,以便任一方均可以經過創建的鏈接將數據推送到另外一端。WebSocket 只須要創建一次鏈接,就能夠一直保持鏈接狀態。

 

輪訓ajax):首先是 ajax輪詢 ,ajax輪詢 的原理很是簡單,讓瀏覽器隔個幾秒就發送一次請求,詢問服務器是否有新信息。

 

長輪訓:其實原理跟 ajax輪詢 差很少,都是採用輪詢的方式,不過採起的是阻塞模型(一直打電話,沒收到就不掛電話),也就是說,客戶端發起鏈接後,若是沒消息,就一直不返回Response給客戶端。直到有消息才返回,返回完以後,客戶端再次創建鏈接,周而復始。

單列模式

 

# 方式一:基於@classmethod
import threading
class Singleton(object):
    instance_clock = threading.Lock()

    def __init__(self):
        pass
    @classmethod
    def instance(cls,*args,**kwargs):
        if not hasattr(Singleton,"_instance"):
            with Singleton.instance_clock:
                if not hasattr(Singleton,"_instance"):
                    Singleton._instance = Singleton(*args,**kwargs)
        return Singleton._instance
# 方式二:基於__new__
import  threading

class Singlton(object):
    def __init__(self):
        pass
    instance_lock = threading.Lock()
    def __new__(cls, *args, **kwargs):
         if not hasattr(Singlton,"_instance"):
             with Singlton.instance_lock:
                 if not hasattr(Singlton,"_instance"):
                     Singlton._instance = object.__new__(cls,*args,**kwargs)

         return Singlton._instance

 

遞歸實現二分查找實例

pass

冒泡排序

def bubble_sort(li):
    for i in range(len(li)-1):
        exchange=False
        for j in range(len(li)-i-1):
            if li[j] >li[j+1]:
                li[j],li[j+1]=li[j+1],li[j]
                exchange=True
        if not exchange:
            return

選擇排序

def select_sort(li):
    for i in range(len(li)-1):
        min_index = i
        for j in range(i+1,len(li)):
            if li[j]<li[min_index]:
                min_index = j
        if min_index != i:
            li[i],li[min_index] = li[min_index],li[i]

解釋什麼叫棧溢出,在什麼狀況下可能出現?

棧是一種後進先出的數據結構,堆棧也是採用這種結構管理內存,調用過程當中當最初的結果依賴於後面的計算處理,那麼後面的部分雖而後開始處理,卻先結束。當後續處理太多而且又依賴更後面的處理......(好比遞歸),便會一直壓棧,當空間所有用完,就會形成「堆棧溢出」。
在Python中,函數調用是經過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。因爲棧的大小不是無限的,因此,遞歸調用的次數過多,會致使棧溢出。

簡述cpython的內存管理機制

包括以下三種機制:
(1)引用計數機制:在Python中,整數和短小的字符,Python都會緩存這些對象,以便重複使用。賦值語句,只是創造了新的引用,而不是對象自己。長的字符串和其它對象能夠有多個相同的對象,可使用賦值語句建立出新的對象。每一個對象都有存有指向該對象的引用總數,即引用計數(reference count)。
(2)垃圾回收機制:引用計數也是一種垃圾收集機制,並且也是一種最直觀,最簡單的垃圾收集技術。當Python的某個對象的引用計數降爲0時,說明沒有任何引用指向該對象,該對象就成爲要被回收的垃圾了。
(3)內存池機制:Python的內存機制呈現金字塔形狀,-1,-2層主要有操做系統進行操做;第0層是C中的malloc,free等內存分配和釋放函數進行操做;第1層和第2層是內存池,有Python的接口函數PyMem_Malloc函數實現,當對象小於256K時有該層直接分配內存;第3層是最上層,也就是咱們對Python對象的直接操做;
Python在運行期間會大量地執行malloc和free的操做,頻繁地在用戶態和核心態之間進行切換,這將嚴重影響Python的執行效率。爲了加速Python的執行效率,Python引入了一個內存池機制,用於管理對小塊內存的申請和釋放。 Python內部默認的小塊內存與大塊內存的分界點定在256個字節,當申請的內存小於256字節時,
PyObject_Malloc會在內存池中申請內存;當申請的內存大於256字節時,PyObject_Malloc的行爲將蛻化爲malloc的行爲。

列舉你知道的python魔法方法及用途

# (1)__getattr__:獲取一個並不存在的屬性的時候就會調用,而若是這個屬性存在則不會調用該方法。以下:
class Test(object):
    def __init__(self, world):
        self.world = world

    def __getattr__(self, item):
        return item


x = Test('world123')
print(x.world)   # 輸出world123
print (x.pppp)   # 輸出pppp


# (2)__getattribute__:比__getattr__更增強大,他能夠攔截全部的屬性獲取行爲。以下:
class Test(object):
    def __init__(self, world):
        self.world = world

    def __getattribute__(self, item):
        print ('get_something: %s' % item)
        return (item)

x = Test(123)
print( x.world)     # get_something: world    world
print(x.pppp)       # get_something: pppp     pppp

# (3)__setattr__:是設置參數的時候會調用到的魔法方法,至關於設置參數前的一個鉤子。每一個設置屬性的方法都繞不開這個魔法方法,只有擁有這個魔法方法的對象才能夠設置屬性。
class Test(object):
    def __init__(self, world):
        self.world = world

    def __setattr__(self, name, value):
        if name == 'value':
            object.__setattr__(self, name, value - 100)
        else:
            print(111)
            object.__setattr__(self, name, value)


x = Test(123)    #實例化時就會執行__setattr__方法
print(x.world)
x.value = 200
print (x.value

# (4)__delattr__:與__setattr__特別類似,執行如 del self.name刪除屬性時,會執行__delattr__
class Test(object):
    def __init__(self, world):
        self.world = world

    def __delattr__(self, item):
        print ('hahaha del something')
        object.__delattr__(self, item)


x = Test(123)
del x.world
print (x.world)   # 報錯

代碼出現如下異常的緣由

IndexError:索引異常,如列表索引取值時,索引不存在會拋此異常
AttributeError:屬性異常,如實例化對象獲取沒有的屬性就會拋出此異常
AssertionError:斷言語句失敗拋出的異常
NotImplementedError:還沒有實現的方法時拋出的異常
StopIteration:迭代器沒有更多值的時候。
TypeError:傳入對象與要求不符    
IndentationError:縮進錯誤

簡述你對GIL的理解

首先明確GIL並非Python的特性,它是在實現Python解析器(CPython)時所引入的一個概念。每次執行python程序,都會開啓一個進程,在此進程不但有主線程,還有主線程開啓的其餘子線程,同時包括垃圾回收等解釋器級別的線程,這些線程在同一個進程,共享進程中的數據。全部的線程訪問解釋器代碼,拿到執行權限,由於解釋器數據共享,因此可能出現垃圾回收在回收解釋器中數據的同時另外一個線程在對數據作修改,這樣就會致使數據的不可靠。爲了解決這個問題,cpython解釋器乾脆給解釋器加一把互斥鎖,每一個線程只有拿到解釋器鎖才能訪問解釋器代碼,其餘線程等待解釋器鎖被釋放後才能訪問,從而保證瞭解釋器級別的數據安全。結論:在Cpython解釋器中,同一個進程下開啓的多線程,同一時刻只能有一個線程執行,沒法利用多核優點。

簡述如下內置函數的用法:reduce  map   any    all

(1)reduce:
    用傳給reduce中的函數 function(有兩個參數)先對集合中的第 一、2 個元素進行操做,獲得的結果再與第三個數據用
    function 函數運算,最後獲得一個結果。
from functools import reduce
def add(x,y):
    return x+y
result = reduce(add,[1,2,3,4,5])
print(result)

(2)map:
    第一個參數 function 以參數序列中的每個元素調用 function 函數,返回包含每次 function 函數返回值的新列表。
    function能夠是一個參數,也能夠是兩個參數,對應的就須要一個或者兩個參數序列。
實例一:
result1 = map(lambda x: x ** 2, [1, 2, 3, 4, 5])
print(result1)          #python3中爲迭代器,python2爲列表
for i in result1:
    print(i)
實例二:
result2 = map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])
print(result2)          #python3中爲迭代器,python2爲列表

(3)any:
    函數用於判斷給定的可迭代參數 iterable 中的全部元素,有一個爲真時返回True,全部爲假時返回False
示例:
print(any([1,0,'']))       #True
print(any([False,0,'']))   #False

(4)all:
    函數用於判斷給定的可迭代參數 iterable 中的全部元素,全部元素爲真時返回True,有一個爲假時返回False

copy和deepcopy的區別是什麼?

python中,變量的存儲採用了引用語義的方式,即變量存儲不是值自己,而是值的內存地址,對於複雜的數據結構,如列表字典等,
變量存儲的是數據結構中每一個值的存儲地址。
使用copy.copy(obj)對對象obj進行淺拷貝,它複製了對象,可是對象中的元素依然使用的是原始引用,因此只要原始引用不發生改
變,原始引用對應的數值發生變化後,也會影響到淺拷貝後的對象。以下實例:

import copy
li=[1,2,3,4]
sourselist=['a','b','c',li]
copylist=copy.copy(sourselist)
li.append('xxx')
print(sourselist)   # ['a', 'b', 'c', [1, 2, 3, 4, 'xxx']]
print(copylist)     # ['a', 'b', 'c', [1, 2, 3, 4, 'xxx']]

使用copy.deepcopy(obj)對對象深拷貝,深拷貝會徹底複製原變量相關的全部數據,在內存中從新開闢一塊空間,無論數據結構
多麼複雜,只要遇到可能發生改變的數據類型,就從新開闢一塊內存空間把內容複製下來,直到最後一層,再也不有複雜的數據類型,就
保持其原引用。在這個過程當中咱們對這兩個變量中的一個進行任意修改都不會影響其餘變量。以下實例:

import copy
li=[1,2,3,4]
sourselist=['a','b','c',li]
copylist=copy.deepcopy(sourselist)
li.append('xxx')
print(sourselist)   # ['a', 'b', 'c', [1, 2, 3, 4, 'xxx']]
print(copylist)     # ['a', 'b', 'c', [1, 2, 3, 4]]

代碼中常常遇到的*args和**kwargs的含義及用法

*arg表明任意個位置參數,**kwargs表明任意個關鍵字參數,使用順序爲def 函數名(位置參數,*args,默認參數,**kwargs),即*arg必定在**kwargs以前。使用見以下實例:

# 實例一:
def test(*args,**kwargs):
    print(args)
    print(kwargs)
test(1,2,a=3,b=4)   # (1, 2)  {'a': 3, 'b': 4}
# 實例二:
def test(*args,**kwargs):
    print(args)
    print(kwargs)
    
li=(1,2)
dic={'a':3,'b':4}
test(*li,**dic)   # (1, 2)  {'a': 3, 'b': 4}

列舉一下你知道的HTTP Header及其功能

Accept:
瀏覽器端能夠接受的媒體類型,通配符 * 表明任意類型
Accept-Encoding:
瀏覽器申明本身接收的編碼方法,例如: Accept-Encoding: zh-CN,zh;q=0.8
Accept-Language:
瀏覽器申明本身接收的語言,
Connection:
如Connection: keep-alive 當一個網頁打開完成後,客戶端和服務器之間用於傳輸HTTP數據的TCP鏈接不會關閉,
若是客戶端再次訪問這個服務器上的網頁,會繼續使用這一條已經創建的鏈接。
Referer:
當瀏覽器向web服務器發送請求的時候,通常會帶上Referer,告訴服務器我是從哪一個頁面連接過來的,服務器籍此能夠得到一些信息用於處理。
User-Agent:
告訴HTTP服務器, 客戶端使用的操做系統和瀏覽器的名稱和版本.
Cookie:
Cookie是用來存儲一些用戶信息以便讓服務器辨別用戶身份的(大多數須要登陸的網站上面會比較常見),好比cookie會存儲一些用戶的用戶名和密碼,
當用戶登陸後就會在客戶端產生一個cookie來存儲相關信息,這樣瀏覽器經過讀取cookie的信息去服務器上驗證並經過後會斷定你是合法用戶,從而容許查看相應網頁。

簡述cookie和session的區別和聯繫

1.cookie是保存在瀏覽器端的鍵值對,而session是保存的服務器端的鍵值對,可是依賴cookie。
2.以登陸爲例,cookie爲經過登陸成功後,設置明文的鍵值對,並將鍵值對發送客戶端存,明文信息可能存在泄漏,不安全。
session則是生成隨機字符串sessionID,發給用戶,並寫到瀏覽器的cookie中,同時服務器本身也會保存一份。
3.在登陸驗證時,cookie:根據瀏覽器發送請求時附帶的cookie的鍵值對進行判斷,若是存在,則驗證經過;
session:在請求用戶的cookie中獲取隨機字符串,根據隨機字符串在session中獲取其對應的值進行驗證

簡述什麼是瀏覽器的同源策略

同源指的是一個請求路徑中的請求協議、ip及端口和另外一個請求路徑中的請求協議、ip及端口保持一致。同源策略是瀏覽器的一個安全功能,
不一樣源的客戶端腳本在沒有明確受權的狀況下,不能讀寫對方資源。

簡述python上下文管理器原理,並用上下文管理器簡單實現將」hello world」,寫入文件的功能。

定義:在使用Python編程中,能夠會常常碰到這種狀況:有一個特殊的語句塊,在執行這個語句塊以前須要先執行一些準備動做;當語句塊執行完成後,須要繼續執行一些收尾動做。如操做文件時,操做前打開文件,操做後關閉文件,對於這些狀況,Python中提供了上下文管理器(Context Manager)的概念,能夠經過上下文管理器來定義/控制代碼塊執行前的準備動做,以及執行後的收尾動做。

原理:建立一個上下文管理器類型的時候,就須要實現__enter__和__exit__方法,在Python中,能夠經過with語句來方便的使用上下文管理器,with語句能夠在代碼塊運行前進入一個運行時上下文(執行__enter__方法),並在代碼塊結束後退出該上下文(執行__exit__方法)。

with open('test.txt',mode='w',encoding='utf-8') as f:
    f.write("hello world")

簡述一致性哈希原理和他要解決的問題

pass

Python中@staticmethod和@classmethod的區別。

在類中總共有三種方法:普通方法(須要參數,使用時默認將類的實例對象傳進去,類調用的時候須要傳遞實例對象),@staticmethod裝飾的靜態方法與普通函數相同(實例和類都可調用,沒有默認的參數傳遞進去),@classmethod裝飾的類方法(須要參數,使用時將調用的類傳進去,或者實例對象調用時是將實例對應的類傳進去。實例:

class Bar():
    def __init__(self, name):
        self.name = name

    a = 'hello'

    def foo(self):
        print(self.name)

    @classmethod
    def classmethod_foo(cls):
        print(cls.a)

    @staticmethod
    def staticmethod_foo():
        print('world')


obj = Bar('lcg')

obj.foo()  # lcg
Bar.foo(obj)  # lcg

obj.classmethod_foo()  # hello
Bar.classmethod_foo()  # hello

obj.staticmethod_foo()  # world
Bar.staticmethod_foo()  # world

Python裏面search()和match()的區別。

首先match()和search()都是隻匹配一個結果,可是match()是從字符串開始處進行匹配,匹配成功返回,沒有返回None而search()則是從頭開始,在整個字符串內匹配。

import re

result1 = re.match('li', 'lichengguangxxx').group()
result2 = re.match('li', 'guangchenglixxx')
print(result1, result2)  # li None

result3 = re.search('li', 'lichengguangxxx').group()
result4 = re.search('li', 'guangchenglixxx').group()
print(result3, result4)  # li li

簡述迭代器和生成器以及他們之間的區別?

迭代器就是用於迭代操做的的對象,聽從迭代協議(內部實現了__iter__()和__next__()方法,能夠像列表(可迭代對象,只有__iter__()方法)同樣迭代獲取其中的值,與列表不一樣的是,構建迭代器的時候,不像列表同樣一次性把數據加到內存,而是以一種延遲計算的方式返回元素,即調用next方法時候返回此值。

生成器本質上也是一個迭代器,本身實現了可迭代協議,與生成器不一樣的是生成器的實現方式不一樣,能夠經過生成器表達式和生成器函數兩種方式實現,代碼更簡潔。生成器和迭代器都是惰性可迭代對象,只能遍歷一次,數據取完拋出Stopiteration異常

菲波那切數列

 

# 計算出前n個fib數列
def fib(n):
    a,b =  1,1
    while n>0:
        n-=1
        yield a
        a,b = b,a+b
print([i for i in fib(10)])
# 計算max以前的fib數列
def fib(max):
    a,b =  1,1
    while a <= max:
        yield a
        a,b = b,a+b
print([i for i in fib(57)])


# 迭代器實現菲波那切數列
class Fib:
    def __init__(self,n):
        self.a = 1
        self.b = 1
        self.n = n
    def __iter__(self):
        return self
    def __next__(self):
        if self.n > 0:
            self.n -= 1
            value = self.a
            self.a,self.b =self.b,self.a +self.b
            return value
        else:
            raise StopIteration()

print([i for i in Fib(10)])

列表表達式與生成器表達式的區別

列表表達式生成是一個列表屬於可迭代對象,數據一次性生成,佔用內存;生成器表達式結果爲一個生成器,具備生成器的特性數據,延遲計算,一次只生成一個結果,只能遍歷一遍,取完拋異常,節省內存。

注意:range()屬於可迭代對象,不是迭代器或生成器,可是是屬於惰性可迭代對象,數據是延遲加載,娶一個生成一個,能夠重複遍歷獲取。

result1 = [i for i in range(10)]
result2 = (i for i in range(10))
print(result1)   # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(result2)   # <generator object <genexpr> at 0x0000021884E24BF8>

什麼是裝飾器?請用裝飾器實現singleton。

裝飾器的本質是一個閉包函數,實現的功能是在不修改原函數及調用方式的狀況下對原函數進行功能擴展的,是開放封閉原則的典型表明。

def wraper(func):
    def inner(*args,**kwargs):
        print("執行函數前擴展的內容")
        ret=func(*args,**kwargs)
        print("執行函數後擴展的內容")
        return ret
    return inner

@wraper
def index(name,age):
    print("我叫%s,今年%s歲" %(name,age))
index("lcg",22)

裝飾器單例:

import threading
class Singleton(object):
    _instance_lock = threading.Lock()
    def __init__(self):
        import time
        time.sleep(3)

    @classmethod
    def instance(cls,*args,**kwagrs):
        if not hasattr(Singleton,'_instance'):
            with Singleton._instance_lock:
                if not hasattr(Singleton, '_instance'):
                    Singleton._instance = Singleton(*args,**kwagrs)
        return Singleton._instance

寫一個簡單的python sockect編程

# 服務端
from socket import socket

server = socket()
server.bind(('127.0.0.1', 8000))
server.listen(5)
while True:
    conn, addr = server.accept()
    while True:
        data = conn.recv(1024)
        print(data.decode('utf-8'))
        conn.send(data.upper())
    conn.close()
server.close()

# 客戶端
from socket import socket

client = socket()
client.connect(('127.0.0.1', 8000))
while True:
    msg = input('>>>').strip()
    if not msg: continue
    client.send(msg.encode('utf-8'))
    data = client.recv(1024).decode('utf-8')
    print('服務端已接收客戶端發來的消息並轉換爲大寫', data)
client.close()

有這樣一段代碼:

a = 10
b = 20
c = [a]
a = 15
print(c)
會輸出什麼,爲何?

如何下代碼(python2.x):

for i in range(1):
    print(i)
for i in xrange(1):
    print(i)

這兩段代碼輸出同樣嗎?佔用系統資源同樣嗎?爲何要用xrange代替range?

結果同樣,可是佔用系統資源不同,range與xrange均屬於可迭代對象,經過循環迭代能夠取出其中的值,可是xrange屬於惰性可迭代對象,雖然不是迭代器,沒有next方法,可是有迭代器同樣的性質,不會一次性將數據加載到內存,而是經過延遲加載的方式生成數據,取一個生成一個,節省內存資源,與python3中的range相同。

有這樣一個url

url:footbar/homework/2009-10-20/xiaoming,其中2009-10-20和xiaoming爲變量,請用正則表達式捕獲這個url,要求儘可能精準.

'^footbar/homework/(?P<date>[0-9]{4}-[0-9]{2}-[0-9]{2})/(?P<name>\w+)$'

當前項目根目錄

import os, sys

# 獲取當前項目根目錄方式一
path1 = os.path.abspath(os.path.dirname(sys.argv[0]))
print(path1)  # D:\WorkSpace\Test
# 獲取當前項目根目錄方式二
path = os.path.dirname(os.path.abspath(__file__))
print(path)  # D:\WorkSpace\Test

現有兩個元組(('a'),('b')),(('c'),('d')),請使用python中匿名函數生成列表[{'a':'c'},{'b':'d'}]

result = map(lambda x, y: {x[0]: y[0]}, (('a'), ('b')), (('c'), ('d')))
print(list(result))  # [{'a': 'c'}, {'b': 'd'}]

# data = zip((('a'), ('b')), (('c'), ('d')))
# print(list(data))  # [('a', 'c'), ('b', 'd')]

django裏Queryset的get和filter方法的區別?

get得到是一個對象,filter獲得是一個對象列表,即便只有一個知足條件

簡述django對http請求的執行流程。

一個 HTTP 請求,首先被轉化成一個 HttpRequest 對象,而後該對象被傳遞給 Request 中間件處理,若是該中間件返回了Response,則直接傳遞給 Response 中間件作收尾處理。不然的話 Request 中間件將訪問 URL 配置,肯定哪一個 view 來處理,在肯定了哪一個 view 要執行,可是尚未執行該 view 的時候,系統會把 request 傳遞給 View 中間件處理器進行處理,若是該中間件返回了Response,那麼該Response 直接被傳遞給 Response 中間件進行後續處理,不然將執行肯定的 View 函數處理並返回 Response,在這個過程當中若是引起了異常並拋出,會被 Exception 中間件處理器進行處理。

簡述django下的(內建的)的緩存機制

緩存是將一些經常使用的數據保存內存或者memcache中,在必定的時間內有人來訪問這些數據時,則再也不去執行數據庫及渲染等操做,而是直接從內存或memcache的緩存中去取得數據,而後返回給用戶.django提供了6中內存緩存機制,分別爲:

開發調試緩存(爲開發調試使用,實際上不使用任何操做);

內存緩存(將緩存內容緩存到內存中);

文件緩存(將緩存內容寫到文件 );
數據庫緩存(將緩存內容存到數據庫);

memcache緩存(包含兩種模塊,python-memcached或pylibmc.)。

以上緩存均提供了三種粒度的應用。

django中model的slugfeild類型字段有什麼用途?

只包含字母、數字、下劃線和鏈接符,一般用於urls

列表的sort方法和sorted的區別是什麼?

list=[-2,1,3,-6],如何實現以絕對值的大小從小到大將list的內容進行排序。

sort 與 sorted 區別:
sort 是應用在 list 上的方法,sorted 能夠對全部可迭代的對象進行排序操做。
list 的 sort 方法返回的是對已經存在的列表進行操做,而內建函數 sorted 方法返回的是一個新的 list,而不是在原來的基礎上進行的操做。

li = [-2, 1, 3, -6]
li.sort()
print(li)  # [-6, -2, 1, 3]

result = sorted(li)
print(result)  # [-6, -2, 1, 3]

# 以絕對值的的大小從小到大排列
result2 = sorted(li, key=lambda x: abs(x))
print(result2)  # [1, -2, 3, -6]

dic = [("a", 2), ("b", 1), ("c", 3)]
result1 = sorted(dic, key=lambda x: x[1])
print(result1)  # [('b', 1), ('a', 2), ('c', 3)]

Python中變量的做用域(變量的查找順序)

python中的做用域分4種狀況:
(1)L:local,局部做用域,即函數中定義的變量;
(2)E:enclosing,嵌套的父級函數的局部做用域,即包含此函數的上級函數的局部做用域,但不是全局的;
(3)G:globa,全局變量,就是模塊級別定義的變量;
(4)B:built-in,系統固定模塊裏面的變量,好比int, bytearray等。
搜索變量的優先級順序依次是:局部做用域>外層做用域>當前模塊中的全局>python內置做用域,也就是LEGB。

Web開發中有哪些技術手段防止sql注入?

sql注入:在sql語句中,若是存在'--'字符,則執行sql語句時會註釋掉--字符後面的內容。凡是有SQL注入漏洞的程序,
都是由於程序要接受來自客戶端用戶輸入的變量或URL傳遞的參數,而且這個變量或參數是組成SQL語句的一部分。放置方式有:
一、使用預編譯綁定變量的SQL語句 如execute()
2.嚴格加密處理用戶的機密信息
3.不要隨意開啓生產環境中Webserver的錯誤顯示
4.使用正則表達式過濾傳入的參數
5.字符串過濾
6.檢查是否包函非法字符

關係型數據庫中,表與表之間有左鏈接、內鏈接、外鏈接,分別指出他們的含義及區別?

一、 交叉鏈接:不使用任何匹配條件生成笛卡爾積
select * from employee,department

二、內鏈接:只鏈接匹配的行
selcet employee.name,employee.age,department.name from employee inner join department on employee.dep_id = department.id
三、外鏈接之左鏈接:優先顯示左表所有內容
selcet employee.name,employee.age,department.name from employee left join department on employee.dep_id = department.id
四、外鏈接之右鏈接:優先顯示右表所有內容
selcet employee.name,employee.age,department.name from employee right join department on employee.dep_id = department.id
五、全外鏈接:顯示左右兩個表所有記錄(mysql不支持full join),實現方式以下:
select * from employee left join department on employee.dep_id = department.id
union
select * from employee right join department on employee.dep_id = department.id

解釋python腳本程序的"__name__"變量及其做用

每個python程序腳本在運行的時候,都有一個__name__屬性,若是程序是做爲模塊被引入的,則其__name__屬性值則自動被設置爲模塊名,若是腳本程序獨立運行,則其__name__屬性則自動被設置爲__main__,利用__name__屬性便可控制python程序的運行方式。

解釋python字符串駐留機制。

Python支持字符串駐留機制,即:對於短字符串,將其賦值給多個不一樣的對象時,內存中只有一個副本,多個對象共享該副本。這一點不適用於長字符串,即長字符串不遵照駐留機制,下面的代碼演示了短字符串和長字符串在這方面的區別。

a = "123"
b = "123"
print(id(a) == id(b))  # True

c = "123" * 50
d = "123" * 50
print(id(c) == id(d))  # False

解釋下HTTP常見響應狀態碼

2XX Success(成功狀態碼)
    200   表示從客戶端發來的請求在服務器端被正常處理
    204   該狀態碼錶示服務器接收的請求已成功處理,但在返回的響應報文中不含實體的主體部分
    206   該狀態碼錶示客戶端進行了範圍請求,而服務器成功執行了這部分的GET請求
3XX Redirection(重定向狀態碼)
    301   永久性重定向
    302   臨時性重定向
4XX Client Error(客戶端錯誤狀態碼)
    400   該狀態碼錶示請求報文中存在語法錯誤
    401   該狀態碼錶示發送的請求須要有經過HTTP認證的認證信息
    403   該狀態碼代表對請求資源的訪問被服務器拒絕了。
    404   該狀態碼代表服務器上沒法找到請求的資源
5XX Server Error(服務器錯誤狀態碼)
    500   該狀態碼代表服務器端在執行請求時發生了錯誤。
    503   該狀態碼代表服務器暫時處於超負載或正在進行停機維護,如今沒法處理請求。

python是如何進行內存管理的

python採用的是基於值的內存管理方式,若是爲不一樣變量賦值相同值,則在內存中只有一份該值,多個變量指向同一塊內存地址

mysql中隨着數據量的增大,查詢速度會愈來愈慢,請給出簡易的優化方案。

1.合理的添加索引(mysql默認只會btree類型索引);
mysql常見的索引:
普通索引INDEX:加速查找

惟一索引:
-主鍵索引PRIMARY KEY:加速查找+約束(不爲空、不能重複)
-惟一索引UNIQUE:加速查找+約束(不能重複)

聯合索引:
-PRIMARY KEY(id,name):聯合主鍵索引
-UNIQUE(id,name):聯合惟一索引
-INDEX(id,name):聯合普通索引
二、避免使用select *
三、建立表時儘可能用char代替varchar
四、表的字段順序,固定長度的優先
五、組合索引代替多個單列索引
六、使用鏈接(join)代替子查詢
七、使用explain優化神器

python自定義棧實例

class Mystack(object):
    def __init__(self):
        self.__items = []

    def size(self):
        return len(self.__items)

    def is_empty(self):
        return self.__items == []

    def push(self, item):
        self.__items.append(item)

    def pop(self):
        return self.__items.pop()

    def peek(self):
        return self.__items[len(self.__items) - 1]


if __name__ == '__main__':
    stack_obj = Mystack()
    stack_obj.push(1)
    stack_obj.push(2)
    stack_obj.push(3)
    print(stack_obj.pop())  # 3
    print(stack_obj.size())  # 2
    print(stack_obj.is_empty())  # Flase

開啓多進程實例

方式1

from multiprocessing import Process
import time, random


def Test(name):
    print("welcome to my house %s" % name)
    time.sleep(random.randint(1, 3))
    print("see you next time %s" % name)


if __name__ == '__main__':
    p1 = Process(target=Test, args=('鳴人',))
    p2 = Process(target=Test, args=('佐助',))
    p3 = Process(target=Test, args=('小櫻',))

    p1.start()
    p2.start()

方式2

from multiprocessing import Process
import time, random, os


class Test(Process):
    def __init__(self, name):
        super().__init__()
        self.name = name

    def run(self):
        print("welcome to my house %s" % self.name, os.getpid())
        time.sleep(random.randint(1, 3))
        print("see you next time %s" % self.name)


if __name__ == '__main__':
    p1 = Test('鳴人')
    p2 = Test('佐助')
    p3 = Test('小櫻')

    p1.start()
    p2.start()
    p3.start()
    print('主進程')

開啓多線程的實例

#方式一
# from threading import Thread
# import time ,random
#
# def Test(name):
#     print('welcome to my house %s' %name)
#     time.sleep(random.randint(1,3))
#     print("see you next time %s" %name)
#
# if __name__ == '__main__':
#     t1 = Thread(target = Test,args=('鳴人',))
#     t2 = Thread(target = Test,args=('佐助',))
#     t3 = Thread(target = Test,args=('小櫻',))
#
#     t1.start()
#     t2.start()
#     t3.start()


#方式二
# from threading import Thread
# import time ,random,os
#
# class Test(Thread):
#     def __init__(self,name):
#         super().__init__()
#         self.name = name
#     def run(self):
#         print('welcome to my house %s' %self.name,os.getpid())
#         time.sleep(random.randint(1,3))
#         print("see you next time %s" %self.name)
#
# if __name__ == '__main__':
#     t1 = Test('鳴人')
#     t2 = Test('佐助')
#     t3 = Test('小櫻')
#
#     t1.start()
#     t2.start()
#     t3.start()
#
#     print('主線程')


from threading import Thread
from socket import socket
import time
s=socket()
s.bind(('127.0.0.1',8000))
s.listen(5)

def action(conn):
    while True:
        data= conn.recv(1024)
        time.sleep(1)
        conn.send(data.upper())
if __name__ == '__main__':
    while True:
        conn,addr= s.accept()
        t=Thread(target=action,args=(conn,))
        t.start()
相關文章
相關標籤/搜索