1. 程式人生 > >python面試常考點

python面試常考點

HTTP協議:
HTTP是超文字傳輸協議的簡稱,他是TCP/IP協議的一個應用層協議,用於定義web瀏覽器與web伺服器之間互動資料的過程。客戶端連上web伺服器後,若想獲得web伺服器中的某個web資源,須遵循一定的通訊格式,HTTP用於定義客戶端與web伺服器之間的通訊格式。

IP
ip作用:用於標識網路上某一臺裝置,網路上不同裝置要進行通訊,IP地址不同


埠作用:是作業系統分配給網路應用程式的編號,當接收到資料後,作業系統會根據編號來講資料轉發到對應編號的應用程式的,用於系統區分網路程式

埠號:就是標識埠的一個編號
知名埠:80埠分配給 HTTP服務
22埠分配給SSH服務
21埠分配給FTP服務

UDP

定義:使用者資料報協議,他是無連線、不可靠的網路傳輸協議
UDP優缺點
優點

1、傳輸速度快
2、不需要連結,資源開銷小
3、由於通訊不需要連結,可以傳送廣播

缺點

1、傳輸資料不可靠,容易丟失資料包
2、沒用流量控制,當對方沒有及時接收資料,傳送方一直髮送資料會導致緩衝區資料滿了,電腦出現卡死情況,所有接受方需要及時接受資料

socket
定義:socket(套接字)是程序間通訊的一個工具,能實現把資料從一方傳輸到另外一方,完成不同電腦上程序之間的通訊,好比資料的搬運工。

資料編碼

str ==> bytes : encode 編碼
bytes ==> str : decode 解碼
字串轉位元組串編碼


位元組串轉字串解碼

  • 其中decode()與encode()方法可以接受引數,其宣告分別為:
bytes.decode(encoding="utf-8",errors="strict")
str.encode(encoding="utf-8",errors="strict")

其中encoding是解碼編碼過程中的使用的編碼格式,errors是指錯誤的處理方式

TCP
tcp是傳輸控制協議,他是一種面向連結的可靠地、基於位元組流的傳輸層通訊協議,用於HTTP、HTTPS、FTP等傳輸檔案協議,
TCP優缺點
優點

TCP在傳輸資料時,,有確認、視窗、重傳阻塞等控制機制,能保證資料正確性、較為可靠

缺點

傳輸速度慢
佔用系統資源高

TCP安全,因為他存在三次握手四次揮手(校驗資料)

通過三次握手的模式,可以是客戶端和伺服器端有效的保持通暢,這樣就可以進行資料傳輸了,資料傳輸完成以後,通過四次揮手的模式,通過客戶端和伺服器端兩次驗證,把資料傳輸結束,這樣保證TCP的安全性

三次握手

(客戶端先發送
連結請求,伺服器端響應客戶端,連線上後客戶端返回連結上資料(listen是讓多人請求時,能進行一個請求等待,最大128連線數)握手沒有完成之前的佇列)

四次揮手

(客戶端發起斷開連結請求,伺服器端返回響應,不立馬斷開連結,等待一段時間後斷開連結,伺服器傳送斷開連結給客戶端,客戶端返回斷開成功)

多工

併發:指的是任務數多於CPU核數,通過作業系統的各種任務排程演算法,實現多個任務一起執行(實際上總有一些任務不在執行,以為任務切換的速度 相當快,看上去一起執行而已)
並行:指的是任務數小於等於CPU核數,即任務真的是一起執行

執行緒(import threading)

def test():
		print("abc")
print(test)  # 這是函式的引用,列印的是記憶體地址
test() # 這是函式的呼叫,列印的是值abc

執行緒的理解
執行緒就是在程式執行過程中,執行程式程式碼的一個分支,每個執行的程式至少都有一個執行緒

執行緒就是執行多工的,是函式的引用,多個函式需要同時執行時使用,一個執行緒就是一個任務,就是一個函式,引用函式時不要加括號,就等於開多個視窗,一個視窗卡住了,其他視窗還可以執行

程式一建立,系統會自動給我們建立一個主執行緒,我們用threading可以開啟一個子執行緒,放入的函式的引用會在子執行緒中執行,在開一個子執行緒將另一個函式的引用放入執行,執行緒之間互不影響,一個執行緒阻塞,另一個執行緒不受影響

 #先匯入threading模組
 # 執行緒中有一個執行緒類,執行緒類中有引數,類加括號呼叫init方法
 sing_thread = threading.Thread(target=sing)
 # 開啟執行緒
 sing_thread.start()

執行緒操作全域性變數
多個執行緒可以操作同一個全域性變數

程序的概念

#匯入執行緒模組
import multiprocessing

程序:通俗理解一個執行的程式或者軟體,程序是作業系統資源分配的基本單位

注意:一個程式至少有一個程序,一個程序至少有一個執行緒,多執行緒可以完成多工

程式一開啟就有一個主程序,主程序內有一個主執行緒,程式碼執行都是執行緒在執行,執行緒是CPU排程的單位,程序是作業系統資源分配的單位

程序之間不共享資料,子程序會複製主程序資源,程序號加ID就是唯一的編號 佇列就是程序用來儲存資料的,存的數量超過限制的數量,會造成阻塞,取得時候超過數量也會造成阻塞

程序、執行緒、協程對比

目標
知道程序和執行緒關係及優缺點

1. 功能對比

程序,能夠完成多工,比如 在一臺電腦上能夠同時執行多個QQ
執行緒,能夠完成多工,比如 一個QQ中的多個聊天視窗

2. 定義對比

  • 程序是系統進行資源分配基本單位,每啟動一個程序作業系統都需要為其分配執行資源。
  • 執行緒是執行程式中的一個執行分支,是CPU排程基本單位。
  • 總結:程序是作業系統資源分配的基本單位,執行緒是CPU排程的基本單位

3. 關係對比

  1. 執行緒是依附在程序裡面的,沒有程序就沒有執行緒
  2. 一個程序預設提供一條執行緒,程序可以建立多個執行緒
  3. 多程序、多執行緒根據cpu核數不一樣可能是並行的,但是協程是在一個執行緒中 所以是併發
  4. 一個執行緒裡面可以有多個協程

4. 區別

  1. 程序之間不共享全域性變數
  2. 執行緒之間共享全域性變數,但是要注意資源競爭的問題,解決辦法: 互斥鎖或者執行緒同步
  3. 建立程序的資源開銷要比建立執行緒的資源開銷要大
  4. 程序是作業系統資源分配的基本單位,執行緒是CPU排程的基本單位
  5. 執行緒不能夠獨立執行,必須依存在程序中
  6. 多程序開發比單程序多執行緒開發穩定性要強

程序、執行緒、協程都是可以完成多工的,可以根據自己實際開發的需要選擇使用
由於執行緒、協程需要的資源很少,所以使用執行緒和協程的機率最大
開闢協程需要的資源最少

優缺點

多程序:

優點:可以用多核
缺點:資源開銷大

多執行緒:

優點:資源開銷小
缺點:不能使用多核

迭代器

  • 迭代:

可以用for迴圈遍歷取值的過程

  • 迭代物件:

使用for迴圈遍歷取值的物件叫做可迭代物件, 比如:列表、元組、字典、集合、range、字串

  • 裝飾器:

本質上是python函式,可以讓其他函式在不需要做任何程式碼變動的前提下增加額外功能,裝飾器的返回值也是一個函式物件

  • 閉包:

在函式內部在定義一個函式,並且這個函式用到了外邊函式的變數,那麼將這個函式以及用到的一些變數稱之為閉包

迭代器必須是可迭代物件

for value in [2, 3, 4]:
    print(value)

可迭代物件

使用for迴圈遍歷取值的物件叫做可迭代物件, 比如:列表、元組、字典、集合、range、字串

    def __iter__(self):
        # 可迭代物件的本質:遍歷可迭代物件的時候其實獲取的是可迭代物件的迭代器, 然後通過迭代器獲取物件中的資料
from collections import Iterable
my_list = MyList()
result = isinstance(my_list, Iterable)
#  Iterable判斷是否是可迭代物件

iter()函式與next()函式

iter函式: 獲取可迭代物件的迭代器,會呼叫可迭代物件身上的__iter__方法
next函式: 獲取迭代器中下一個值,會呼叫迭代器物件身上的__next__方法
自定義迭代器物件: 在類裡面定義__iter__和__next__方法建立的物件就是迭代器物件

# 自定義一個類去判斷當前的類是否可以被迭代

from  collections import Iterable  # 可迭代的物件


# 只要類實現iter,那麼這個類就可以被迭代
# 只要類實現了iter 跟next這兩個方法就是迭代器了
class MyIter(object):
	# 初始化值
	def __init__(self):
		self.value = 0  # 初始化的值

	# 這個返回迭代器物件
	def __iter__(self):
		return self  # 這個以後自定義迭代器固定寫法就是返回self

	# 返回迭代的資料
	def __next__(self):
		# 手動丟擲異常

		# 每一次資料都 增長
		self.value += 1
		# 到十停止
		if self.value > 10:
			# 停止 迭代
			raise StopIteration

		return self.value


# 得到一個物件
my_iter = MyIter()

# print(isinstance(my_iter, Iterable))
# 這個類是一個可迭代的物件,但是他還不能被迭代,因為他沒有返回迭代的資料
# 如果你要使用for,那麼你一定要是一個迭代器物件,迭代器前提是你是可迭代的物件,但是再加一個返回資料

for temp in my_iter:
	print(temp)

迭代器與列表的區別

迭代器是在裡面寫了一個公式,而不是將資料真正的存進來,在記憶體使用上比列表效率更高一點。列表是將所要資料迴圈遍歷一遍,佔用記憶體比較嚴重

for迴圈底層

是iter和next一步步拆分出來的

# for 迴圈的底層
# 生成一個一百萬的資料遍歷

class MyIter(object):
	# 實現兩個方法iter,next

	# 初始化值
	def __init__(self):
		self.start = 0  # 初始化起始值

	def __iter__(self):
		return self  # 返回自身

	def __next__(self):
		# 判斷是如果到了一百萬那麼手動丟擲停止迭代的異常
		if self.start > 1000000:
			# 停止迭代
			raise StopIteration

		self.start += 1

		return self.start


my_iter = MyIter()

# for temp in my_iter:
# 	print(temp)

# 得到我們的迭代器物件
my_iter_object = iter(my_iter)
# iter next拆分得到for迴圈,是一個一個next遍歷出來的

# 得到迭代的資料
print(next(my_iter_object))
print(next(my_iter_object))
print(next(my_iter_object))

生成器

生成器就是迭代器,迭代器必須是可迭代物件,生成器生成的方式不一樣
生成器不需要定義類,
生成器第一種方式

# 生成器是一種特殊的迭代器,特殊在於他的生成的方式不能通過類實現iter跟next

# 列表推導式
a_list = [x for x in range(10)]

# print(a_list)


# 把列表推導式的[]改成()就是生成器了
# 瞭解一下
a_list = (x for x in range(10))

print(a_list)

for temp in a_list:
	print(temp)

生成器第二種方式
gevent的底層就是yield,可以使兩個函式之間來回切換,因為next使函式執行了一次,然後在執行另一個函式,就實現了兩個函式的來回切換,但是需要有耗時任務,沒有耗時任務是無法來回切換

# 使用函式生成器,把return 換成yield就是生成器了
# 只要函式中有yield那麼就是生成器了

def count():
	for temp in range(10):
		yield temp  # yield能讓我們的函式暫停執行


print(count())

# 得到器物件
count_iter = iter(count())
# 迭代
print(next(count_iter))
print(next(count_iter))
print(next(count_iter))
print(next(count_iter))
print(next(count_iter))
print(next(count_iter))

閉包

# 格式
# 兩個函式巢狀, 外部函式返回內部函式的引用,一般外部函式都有引數,外部引數的值會一直保留在記憶體中
def 外部函式(引數):
	def 內部函式():
		# 讓函式做一些事情
		print(引數)

	return 內部函式


內部函式的引用 = 外部函式("傳入引數")
# 執行內部的函式
內部函式的引用()

裝飾器

def set_fun(func):
	def call_fun(*args, **kwargs):
		print("裝飾一把")
		return func(*args, **kwargs)

	return call_fun
	
@set_fun
def test():
	print("test")


test()

多個裝飾器裝飾一個函式
執行順序是先上後下,先外後內

def set_fun1(func1):
	print("set_fun1")

	def call_fun1():
		print("call_fun1")
		func1()

	return call_fun1


def set_fun2(func2):
	print("set_fun2")

	def call_fun2():
		print("call_fun2")
		func2()

	return call_fun2


@set_fun2
@set_fun1
def test():
	print("test")


test()

gil鎖

gil全域性直譯器鎖 ,是python直譯器歷史遺留問題,跟python語言沒有什麼關係,換一個jpython就沒有這個問題了。不用執行緒用程序

對多執行緒的影響,在同一時刻只有一個執行緒執行,這些執行緒在一同個程序內

並闡明多執行緒抓取程式是否可比單執行緒效能有提升,多執行緒還是可以用到多核的資源,但是爬蟲是一個阻塞的東西,網路的速度比CPU的速度慢很多,

任何Python執行緒執行前,必須先獲得GIL鎖,然後,每執行100條位元組碼,直譯器就自動釋放GIL鎖,讓別的執行緒有機會執行

Python雖然不能利用多執行緒實現多核任務,但可以通過多程序實現多核任務

拷貝與引用的區別

引用:是兩個變數值,指向同一個記憶體地址
拷貝:是會生成一個新的記憶體地址
在這裡插入圖片描述

淺拷貝

拷貝了最外圍的物件本身,內部的元素都只是拷貝了一個引用而已。也就是,把物件複製一遍,但是該物件中引用的其他物件我不復制

深拷貝

外圍和內部元素都進行了拷貝物件本身,而不是引用。也就是,把物件複製一遍,並且該物件中引用的其他物件我也複製。

切片與深淺拷貝

1.切片可以應用於:列表、元組、字串,但不能應用於字典。
2.深淺拷貝,既可應用序列(列表、元組、字串),也可應用字典。

深淺拷貝的作用

1,減少記憶體的使用
2,以後在做資料的清洗、修改或者入庫的時候,對原資料進行復制一份,以防資料修改之後,找不到原資料。

單例模式
使一個類只能建立一個物件,建立單例時只執行一次__init__方法

class Person(object):
    instance = None
    is_first_run = True

    def __new__(cls, *args, **kwargs):
        if cls.instance == None:
            cls.instance = object.__new__(cls)
        return cls.instance

    def __init__(self, name=''):
        if Person.is_first_run:
            self.name = name  # 只有第一次建立物件才應該賦值
            Person.is_first_run = False

    def set_name(self, new_name):
        self.name = new_name


zs = Person('張三')
print(zs.name)

li = Person()
print(li.name)
li.set_name('李思')
print(zs.name)

flask和Django路由對映的區別

索引:

是一種特殊的檔案(InnoDB資料表上的索引是表空間的一個組成部分),它們包含著對資料表裡所有記錄的位置資訊。如火車站的車次表、圖書的目錄等

資料庫優化
1、使用索引(B+樹、hash)

應 儘量避免全表掃描,首先應考慮在order,group by 涉及的列上建立索引

2、優化SQL語句

通過explain(查詢優化神器)用來檢視SQL語句的執行效果,可以幫助寫出更 好的SQL語句: (1)避免使用select * from,用具體的欄位代替 *,不要返回用不到的任何欄位 (2)不在索引列做運算或者使用函式
(3)儘量使用limit減少返回的行數,減少資料傳輸時間和頻寬浪費

3、優化資料庫物件

(1)使用procedure
analyse()函式對錶進行分析,該函式可以對錶中列的資料型別提出優化建議,使用能正確的表示和儲存資料的最短型別,這樣可以減少對磁碟空間。記憶體。CPU快取的使用

4、使用快取

把經常訪問的且不需要經常變化的資料放在快取中能節約磁碟的IO

5、主從複製、讀寫分離、負載均衡

6、分散式

函式裝飾器有什麼作用(常考)

裝飾器本質上是一個Python函式,它可以讓其他函式在不需要做任何程式碼變動的前提下增加額外功能,裝飾器的返回值也是一個函式物件。它經常用於有切面需求的場景,比如:插入日誌、效能測試、事務處理、快取、許可權校驗等場景。有了裝飾器,就可以抽離出大量與函式功能本身無關的雷同程式碼並繼續重用。