【python web開發知識點整理1】- Python基礎

【python web開發知識點整理1】- Python基礎
【python web開發知識點整理2】- Python Web基礎
【python web開發知識點整理3】- 容器基礎
【python web開發知識點整理4】- 數據庫基礎
【python web開發知識點整理5】- Linux基礎
【python web開發知識點整理6】- 設計模式

1. Python基礎

1.1. PEP8是什麼?

PEP8是Python編碼風格指南,即 Style Guide for Python Code。一些關於如何讓你的程序更具有可讀性的建議。

1.2. Python之禪(import this)是什麼?

Python shell 裏執行一下:import this,是作者對開發者的建議。

1.3. Python常用的容器類型有哪些以及它們之間的差別?

常用的容器類型list、tuple、dict、set等。

  1. list是可變類型,其大小可以改變,其元素是對象的引用。
  2. tuple是不可變類型,其大小創建後可以改變,其元素是對象的引用。
  3. dict是可變類型,字典可以存儲鍵值對但鍵必須唯一,只有可哈希的對象可以做鍵,其元素是對象的引用。
  4. set是可變類型,可以理解爲特殊的字典,只存儲鍵且是唯一的。

list和tuple的差別:
list一個是可變的,tuple是不可變的

set、dict和list、tuple的差別:

  1. set、dict是無序的,鍵是哈希後再排序進行存儲的,插入順序和輸出順序不一致,
    list、tulpe是有序的。
  2. 獲取方式不同,list、tulpe可以通過索引獲取,可以切片,dict通過鍵獲取
  3. 對於key來說,set、dict是存放元素是唯一的,不能重複的,list、tulpe是可重複的
  4. 可變類型不同
  5. 查詢速度不同

還有一些常用的容器類型,比如OrderedDict可以解決字典無序的問題

1.4. 解釋下閉包是什麼,以及日常中什麼場景會用到?

1.4.1 閉包的條件

  1. 在一個外函數中定義了一個內函數。
  2. 內函數裏運用了外函數的臨時變量。
  3. 並且外函數的返回值是內函數的引用

1.4.2 最常用到的是裝飾器

可以通過裝飾器做數據緩存、打印日誌、判斷參數合法性等。

1.5. GIL是什麼?它的影響和具體原理是什麼?

GIL:Global Interpreter Lock(全局解釋器鎖)。
在一個進程中,同一時刻只能有一個線程能到解釋器,爲什麼只能有一個線程拿到解釋器呢?因爲在 CPython 中,內存管理不是線性安全的,所以,爲了避免多個線程同時訪問到一個對象,就有了這麼一個鎖,即全局解釋器鎖。

1.5.1. 那麼 Python 中有哪些類型是線程安全的呢?

Python中基本數據類型list, dict, tuple等都是線程安全的。

1.5.2. 那麼 GIL 的影響是什麼呢?

就是同一時刻只有一個線程在真實執行,對於CPU密集型的應用影響比較大,對於IO密集型的應用影響沒那麼大。
一個磁盤或網絡爲主的程序稱爲IO密集型的應用,一個計算爲主的程序稱爲CPU密集型的應用,計算爲主的程序利用多cup處理多進程來提供計算速度,但只有一個線程可以真實執行,其他CPU會閒置,所以影響比較大。

1.6. 進程、協程、線程分別是什麼,以及區別是什麼?

從操作系統角度來講,進程是資源分配單元,線程是執行單元,多個線程可以共享所在進程的資源。而協程是從程序運行角度來叫,是由用戶(程序)控制和調度的一個過程,在 Python中,協程是一個包含了yield的函數,包含yield的函數也被稱爲生成器。

協程看上去也是子程序,但執行過程中,在子程序內部可中斷,然後轉而執行別的子程序,在適當的時候再返回來接着執行。
注意,在一個子程序中中斷,去執行其他子程序,不是函數調用,有點類似CPU的中斷。

最大的優勢就是協程極高的執行效率。因爲子程序切換不是線程切換,而是由程序自身控制,因此,沒有線程切換的開銷,和多線程比,線程數量越多,協程的性能優勢就越明顯。
第二大優勢就是不需要多線程的鎖機制,因爲只有一個線程,也不存在同時寫變量衝突,在協程中控制共享資源不加鎖,只需要判斷狀態就好了,所以執行效率比多線程高很多。
因爲協程是一個線程執行,那怎麼利用多核CPU呢?最簡單的方法是多進程+協程,既充分利用多核,又充分發揮協程的高效率,可獲得極高的性能。

yield

Python通過yield提供了對協程的基本支持,但是不完全。而第三方的gevent爲Python提供了比較完善的協程支持。

gevent

gevent是第三方庫,通過greenlet實現協程,其基本思想是:
當一個greenlet遇到IO操作時,比如訪問網絡,就自動切換到其他的greenlet,等到IO操作完成,再在適當的時候切換回來繼續執行。由於IO操作非常耗時,經常使程序處於等待狀態,有了gevent爲我們自動切換協程,就保證總有greenlet在運行,而不是等待IO。

1.7. 面向對象設計六大原則?

  1. 單一職責原則——SRP
  2. 開閉原則——OCP
  3. 裏式替換原則——LSP
  4. 依賴倒置原則——DIP
  5. 接口隔離原則——ISP
  6. 迪米特原則——LOD

1.7.1. 單一職責原則

單一職責原則,Single Responsibility Principle,簡稱SRP。
其定義是應該有且僅有一個類引起類的變更,這話的意思就是一個類只擔負一個職責。
優點:

  • 類的複雜性降低,實現什麼職責都有明確的定義;
  • 邏輯變得簡單,類的可讀性提高了,而且,因爲邏輯簡單,代碼的可維護性也提高了;
  • 變更的風險降低,因爲只會在單一的類中的修改。

1.7.2. 開-閉原則

開閉原則,Open Closed Principle,是Java世界裏最基礎的設計原則,其定義是:
一個軟件實體如類、模塊和函數應該對擴展開放,對修改關閉
也就是說,一個軟件實體應該通過擴展來實現變化,而不是通過修改已有的代碼實現變化。這是爲軟件實體的未來事件而制定的對現行開發設計進行約束的一個原則。
在我們編碼的過程中,需求變化是不斷的發生的,當我們需要對代碼進行修改時,我們應該儘量做到能不動原來的代碼就不動,通過擴展的方式來滿足需求。
優點:
降低了程序各部分之間的耦合性,其適應性、靈活性、穩定性都比較好。當已有軟件系統需要增加新的功能時,不需要對作爲系統基礎的抽象層進行修改,只需要在原有基礎上附加新的模塊就能實現所需要添加的功能。增加的新模塊對原有的模塊完全沒有影響或影響很小,這樣就無須爲原有模塊進行重新測試。

1.7.3. 里氏代換原則

里氏替換原則,英文名Liskov Substitution Principle,它的定義是
如果對每一個類型爲T1的對象o1,都有類型爲T2的對象o2,使得以T1定義的所有程序P在所有對象o1都替換成o2的時候,程序P的行爲都沒有發生變化,那麼類型T2是類型T1的子類型。
看起來有點繞口,它還有一個簡單的定義:
所有引用基類的地方必須能夠透明地使用其子類的對象。
優點:
可以很容易的實現同一父類下各個子類的互換,而客戶端可以毫不察覺。

1.7.4. 依賴倒換原則

依賴倒置原則,Dependence Inversion Principle,簡稱DIP,它的定義是:
高層模塊不應該依賴底層模塊,兩者都應該依賴其抽象;
抽象不應該依賴細節;
細節應該依賴抽象;
優點:
人的思維本身實際上就是很抽象的,我們分析問題的時候不是一下子就考慮到細節,而是很抽象的將整個問題都構思出來,所以面向抽象設計是符合人的思維的。另外這個原則會很好的支持(開閉原則)OCP,面向抽象的設計使我們能夠不必太多依賴於實現,這樣擴展就成爲了可能,這個原則也是另一篇文章《Design by Contract》的基石。

1.7.5. 接口隔離原則

接口隔離原則,Interface Segregation Principle,簡稱ISP,其定義是:

客戶端不應該依賴它不需要的接口
優點:
會使一個軟件系統功能擴展時,修改的壓力不會傳到別的對象那裏。

1.7.6. 迪米特法則或最少知識原則

迪米特原則,Law of Demeter,簡稱LoD,也被稱爲最少知識原則,它描述的規則是:
一個對象應該對其他對象有最少的瞭解
優點:
消除耦合。

1.8. 解釋下什麼是 ORM 以及它的優缺點是什麼?

ORM是Object Relational Mapping(對象關係映射)
它做的事就是幫我們封裝一下對數據庫的操作,避免我們來寫不太好維護的SQL代碼。
優點:
使用ORM寫的代碼更容易維護,因爲裏面不用夾雜着各種SQL代碼。
缺點:
失去了 SQL 的靈活,並且越是通用的 ORM 框架,性能損耗會越大。

1.9. 深拷貝和淺拷貝的區別是什麼?

深拷貝是將對象本身複製給另一個對象。這意味着如果對對象的副本進行更改時不會影響原對象。在 Python 中,我們使用 deepcopy()函數進行深拷貝。
淺拷貝是將對象的引用複製給另一個對象。因此,如果我們在副本中進行更改,則會影響原對象。使用 copy()函數進行淺拷貝。

1.10. 解釋 Python 中的三元表達式

[on true] if [expression]else [on false]

如果 [expression] 爲真, 則 [on true] 部分被執行。如果表示爲假則 [on false] 部分被執行

1.11. Python 中如何實現多線程?

python主要是通過thread和threading這兩個模塊來實現多線程支持。
_thread提供了低級別的、原始的線程以及一個簡單的鎖,它相比於threading模塊的功能還是比較有限的,可以更加方便的被使用。但是python(cpython)由於GIL的存在無法使用threading充分利用CPU資源,如果想充分發揮多核CPU的計算能力需要使用multiprocessing模塊(Windows下使用會有諸多問題)。

1.12. 解釋繼承

一個類繼承自另一個類,也可以說是一個孩子類/派生類/子類,繼承自父類/基類/超類,同時獲取所有的類成員(屬性和方法)。
繼承使我們可以重用代碼,並且還可以更方便地創建和維護代碼。Python支持以下類型的繼承:

  1. 單繼承- 一個子類類繼承自單個基類
  2. 多重繼承- 一個子類繼承自多個基類
  3. 多級繼承- 一個子類繼承自一個基類,而基類繼承自另一個基類
  4. 分層繼承- 多個子類繼承自同一個基類
  5. 混合繼承- 兩種或兩種以上繼承類型的組合

1.13. Python是如何進行內存管理的?

1.13.1. 引用計數:

Pyhton的內部使用引用計數,來保持內存中的對象,所有對象都有引用計數。

  1. 引用計數增加:

    • 一個對象分配一個新名稱
    • 將其放入一個容器中(列表、元素或字典)
  2. 引用減少的情況

    1. 使用del語句將對象的別名顯式的銷燬
    2. 引用被重新賦值
    3. 獲取應用對象:
    4. 通過sys.getrefcount()函數獲取某個引用的引用數,函數參數實際上創建了一個臨時的引用。因此,getrefcount( )所得到的結果,會比期望多1。

1.13.2. 垃圾回收:

  1. 當一個對象的引用計數歸零時,它將被垃圾回收機制處理掉
  2. python的自動垃圾回收:當分配對象的次數和取消分配對象的次數的差值高於某個閾值時,垃圾回收纔會啓動。

1.13.2.1 標記清除

『標記清除(Mark—Sweep)』算法是一種基於追蹤回收(tracing GC)技術實現的垃圾回收算法。它分爲兩個階段:第一階段是標記階段,GC會把所有的『活動對象』打上標記,第二階段是把那些沒有標記的對象『非活動對象』進行回收。那麼GC又是如何判斷哪些是活動對象哪些是非活動對象的呢?

對象之間通過引用(指針)連在一起,構成一個有向圖,對象構成這個有向圖的節點,而引用關係構成這個有向圖的邊。從根對象(root object)出發,沿着有向邊遍歷對象,可達的(reachable)對象標記爲活動對象,不可達的對象就是要被清除的非活動對象。根對象就是全局變量、調用棧、寄存器。

在這裏插入圖片描述

在上圖中,我們把小黑圈視爲全局變量,也就是把它作爲root object,從小黑圈出發,對象1可直達,那麼它將被標記,對象2、3可間接到達也會被標記,而4和5不可達,那麼1、2、3就是活動對象,4和5是非活動對象會被GC回收。

標記清除算法作爲Python的輔助垃圾收集技術主要處理的是一些容器對象,比如list、dict、tuple,instance等,因爲對於字符串、數值對象是不可能造成循環引用問題。Python使用一個雙向鏈表將這些容器對象組織起來。不過,這種簡單粗暴的標記清除算法也有明顯的缺點:清除非活動的對象前它必須順序掃描整個堆內存,哪怕只剩下小部分活動對象也要掃描所有對象。

1.13.2.2 分代回收

python將內存根據對象的存活時間分爲不同的集合,每個集合稱爲一代,python將內存分爲了3代。分別爲 年輕代(第0代)、中年代(第1代)、老年代(第2代)
這三代分別對應的是三個鏈表
新創建的對象會被分配在年輕代。年輕代鏈表總數達到上限的時候,python的垃圾回收機制就會觸發,把那些可以被回收的對象回收掉,而那些不會回收的對象就會被移到中年代去。以此類推,老年代中的對象是存活時間最久的對象
分代回收建立在標記清除的技術基礎上

分代回收是一種以空間換時間的操作方式,Python將內存根據對象的存活時間劃分爲不同的集合,每個集合稱爲一個代,Python將內存分爲了3“代”,分別爲年輕代(第0代)、中年代(第1代)、老年代(第2代),他們對應的是3個鏈表,它們的垃圾收集頻率與對象的存活時間的增大而減小。新創建的對象都會分配在年輕代,年輕代鏈表的總數達到上限時,Python垃圾收集機制就會被觸發,把那些可以被回收的對象回收掉,而那些不會回收的對象就會被移到中年代去,依此類推,老年代中的對象是存活時間最久的對象,甚至是存活於整個系統的生命週期內。同時,分代回收是建立在標記清除技術基礎之上。分代回收同樣作爲Python的輔助垃圾收集技術處理那些容器對象

1.13.2.2 三種觸發垃圾回收的情況

調用gc.collect(),需要先導入gc模塊
當gc模塊的計數器達到閾值的時候
程序退出時

1.13.3. 內存池機制

Python的內存垃圾回收機制,將不用的內存放到內存池而不是返回給操作系統。

  1. Pymalloc機制。爲了加速Python的執行效率,Python引入內存池機制,用於管理對小塊內存的管理和釋放。
  2. 對於所有小於256個字節的對象都使用pymalloc實現的分配器;而大於這個長度的對象則使用系統的malloc。
  3. 對於Python對象,如整數、浮點數和List,都有其獨立的私有內存池,對象間不共享他們的內存池。如果你分配又釋放了大量的整數,用於緩存這些整數的內存不能再分配給浮點數。

1.14. 描述數組、鏈表、隊列、堆棧的區別?

數組與鏈表是數據存儲方式的概念,數組在連續的空間中存儲數據,而鏈表可以在非連續的空間中存儲數據;
隊列和堆棧是描述數據存取方式的概念,隊列是先進先出,而堆棧是後進先出;
隊列和堆棧可以用數組來實現,也可以用鏈表實現。

1.15. 當退出Python時是否釋放所有內存分配?

具有對象循環引用或者全局命名空間引用的變量,在Python退出是往往不會被釋放。
另外不會釋放C庫保留的部分內容。

1.16. 什麼是猴子補丁?

在運行時動態修改類和模塊。

1.17. 能否解釋一下 *args 和 **kwargs?

如果我們不知道將多少個參數傳遞給函數,比如當我們想傳遞一個列表或一個元組值時,就可以使用*args。
當我們不知道將會傳入多少關鍵字參數時,使用**kwargs 會收集關鍵字參數。
使用 args 和 kwargs 作爲參數名只是舉例,可以任意替換。

1.18. 什麼是負索引?

Python中的序列索引可以是正也可以是負。如果是正索引,0是序列中的第一個索引,1是第二個索引。如果是負索引,(-1)是最後一個索引而(-2)是倒數第二個索引。

python中的構造方法和初始化方法的區別?

對於類的 new 方法和 init 方法可以概括爲:
new 方法是Python的新式類中真正的構造方法,負責創建並返回實例,因此,new 方法必須要有返回值;
init 方法是初始化方法,負責初始化 new 方法返回的實例對象。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章