日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > python >内容正文

python

一份Python面试宝典

發(fā)布時(shí)間:2023/12/18 python 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一份Python面试宝典 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Python面試寶典

文章目錄

    • Python面試寶典
        • 題目001: 在Python中如何實(shí)現(xiàn)單例模式。
        • 題目002:不使用中間變量,交換兩個(gè)變量`a`和`b`的值。
        • 題目003:寫(xiě)一個(gè)刪除列表中重復(fù)元素的函數(shù),要求去重后元素相對(duì)位置保持不變。
        • 題目004:假設(shè)你使用的是官方的CPython,說(shuō)出下面代碼的運(yùn)行結(jié)果。
        • 題目005:Lambda函數(shù)是什么,舉例說(shuō)明的它的應(yīng)用場(chǎng)景。
        • 題目006:說(shuō)說(shuō)Python中的淺拷貝和深拷貝。
        • 題目007:Python是如何實(shí)現(xiàn)內(nèi)存管理的?
        • 題目008:說(shuō)一下你對(duì)Python中迭代器和生成器的理解。
        • 題目009:正則表達(dá)式的match方法和search方法有什么區(qū)別?
        • 題目010:下面這段代碼的執(zhí)行結(jié)果是什么。
        • 題目011:Python中為什么沒(méi)有函數(shù)重載?
        • 題目012:用Python代碼實(shí)現(xiàn)Python內(nèi)置函數(shù)max。
        • 題目013:寫(xiě)一個(gè)函數(shù)統(tǒng)計(jì)傳入的列表中每個(gè)數(shù)字出現(xiàn)的次數(shù)并返回對(duì)應(yīng)的字典。
        • 題目014:使用Python代碼實(shí)現(xiàn)遍歷一個(gè)文件夾的操作。
        • 題目015:現(xiàn)有2元、3元、5元共三種面額的貨幣,如果需要找零99元,一共有多少種找零的方式?
        • 題目016:寫(xiě)一個(gè)函數(shù),給定矩陣的階數(shù)`n`,輸出一個(gè)螺旋式數(shù)字矩陣。
        • 題目017:閱讀下面的代碼,寫(xiě)出程序的運(yùn)行結(jié)果。
        • 題目018:說(shuō)出下面代碼的運(yùn)行結(jié)果。
        • 題目19:說(shuō)說(shuō)你用過(guò)Python標(biāo)準(zhǔn)庫(kù)中的哪些模塊。
        • 題目20:`__init__`和`__new__`方法有什么區(qū)別?
        • 題目21:輸入年月日,判斷這個(gè)日期是這一年的第幾天。
        • 題目22:平常工作中用什么工具進(jìn)行靜態(tài)代碼分析。
        • 題目23:說(shuō)一下你知道的Python中的魔術(shù)方法。
        • 題目24:函數(shù)參數(shù)`*arg`和`**kwargs`分別代表什么?
        • 題目25:寫(xiě)一個(gè)記錄函數(shù)執(zhí)行時(shí)間的裝飾器。
        • 題目26:什么是鴨子類(lèi)型(duck typing)?
        • 題目27:說(shuō)一下Python中變量的作用域。
        • 題目28:說(shuō)一下你對(duì)閉包的理解。
        • 題目29:說(shuō)一下Python中的多線(xiàn)程和多進(jìn)程的應(yīng)用場(chǎng)景和優(yōu)缺點(diǎn)。
        • 題目30:說(shuō)一下Python 2和Python 3的區(qū)別。
        • 題目31:談?wù)勀銓?duì)“猴子補(bǔ)丁”(monkey patching)的理解。
        • 題目32:閱讀下面的代碼說(shuō)出運(yùn)行結(jié)果。
        • 題目33:編寫(xiě)一個(gè)函數(shù)實(shí)現(xiàn)對(duì)逆波蘭表達(dá)式求值,不能使用Python的內(nèi)置函數(shù)。
        • 題目34:Python中如何實(shí)現(xiàn)字符串替換操作?
        • 題目35:如何剖析Python代碼的執(zhí)行性能?
        • 題目36:如何使用`random`模塊生成隨機(jī)數(shù)、實(shí)現(xiàn)隨機(jī)亂序和隨機(jī)抽樣?
        • 題目37:解釋一下線(xiàn)程池的工作原理。
        • 題目38:舉例說(shuō)明什么情況下會(huì)出現(xiàn)`KeyError`、`TypeError`、`ValueError`。
        • 題目39:說(shuō)出下面代碼的運(yùn)行結(jié)果。
        • 題目40:如何讀取大文件,例如內(nèi)存只有4G,如何讀取一個(gè)大小為8G的文件?
        • 題目41:說(shuō)一下你對(duì)Python中模塊和包的理解。
        • 題目42:說(shuō)一下你知道的Python編碼規(guī)范。
        • 題目43:運(yùn)行下面的代碼是否會(huì)報(bào)錯(cuò),如果報(bào)錯(cuò)請(qǐng)說(shuō)明哪里有什么樣的錯(cuò),如果不報(bào)錯(cuò)請(qǐng)說(shuō)出代碼的執(zhí)行結(jié)果。
        • 題目44:對(duì)下面給出的字典按值從大到小對(duì)鍵進(jìn)行排序。
        • 題目45:說(shuō)一下`namedtuple`的用法和作用。
        • 題目46:按照題目要求寫(xiě)出對(duì)應(yīng)的函數(shù)。
        • 題目47:按照題目要求寫(xiě)出對(duì)應(yīng)的函數(shù)。
        • 題目48:按照題目要求寫(xiě)出對(duì)應(yīng)的裝飾器。
        • 題目49:寫(xiě)一個(gè)函數(shù)實(shí)現(xiàn)字符串反轉(zhuǎn),盡可能寫(xiě)出你知道的所有方法。
        • 題目50:按照題目要求寫(xiě)出對(duì)應(yīng)的函數(shù)。

題目001: 在Python中如何實(shí)現(xiàn)單例模式。

點(diǎn)評(píng):單例模式是指讓一個(gè)類(lèi)只能創(chuàng)建出唯一的實(shí)例,這個(gè)題目在面試中出現(xiàn)的頻率極高,因?yàn)樗疾斓牟粌H僅是單例模式,更是對(duì)Python語(yǔ)言到底掌握到何種程度,建議大家用裝飾器和元類(lèi)這兩種方式來(lái)實(shí)現(xiàn)單例模式,因?yàn)檫@兩種方式的通用性最強(qiáng),而且也可以順便展示自己對(duì)裝飾器和元類(lèi)中兩個(gè)關(guān)鍵知識(shí)點(diǎn)的理解。

方法一:使用裝飾器實(shí)現(xiàn)單例模式。

from functools import wrapsdef singleton(cls):"""單例類(lèi)裝飾器"""instances = {}@wraps(cls)def wrapper(*args, **kwargs):if cls not in instances:instances[cls] = cls(*args, **kwargs)return instances[cls]return wrapper@singleton class President:pass

擴(kuò)展:裝飾器是Python中非常有特色的語(yǔ)法,用一個(gè)函數(shù)去裝飾另一個(gè)函數(shù)或類(lèi),為其添加額外的能力。通常通過(guò)裝飾來(lái)實(shí)現(xiàn)的功能都屬橫切關(guān)注功能,也就是跟正常的業(yè)務(wù)邏輯沒(méi)有必然聯(lián)系,可以動(dòng)態(tài)添加或移除的功能。裝飾器可以為代碼提供緩存、代理、上下文環(huán)境等服務(wù),它是對(duì)設(shè)計(jì)模式中代理模式的踐行。在寫(xiě)裝飾器的時(shí)候,帶裝飾功能的函數(shù)(上面代碼中的wrapper函數(shù))通常都會(huì)用functools模塊中的wraps再加以裝飾,這個(gè)裝飾器最重要的作用是給被裝飾的類(lèi)或函數(shù)動(dòng)態(tài)添加一個(gè)__wrapped__屬性,這個(gè)屬性會(huì)將被裝飾之前的類(lèi)或函數(shù)保留下來(lái),這樣在我們不需要裝飾功能的時(shí)候,可以通過(guò)它來(lái)取消裝飾器,例如可以使用President = President.__wrapped__來(lái)取消對(duì)President類(lèi)做的單例處理。需要提醒大家的是:上面的單例并不是線(xiàn)程安全的,如果要做到線(xiàn)程安全,需要對(duì)創(chuàng)建對(duì)象的代碼進(jìn)行加鎖的處理。在Python中可以使用threading模塊的RLock對(duì)象來(lái)提供鎖,可以使用鎖對(duì)象的acquire和release方法來(lái)實(shí)現(xiàn)加鎖和解鎖的操作。當(dāng)然,更為簡(jiǎn)便的做法是使用鎖對(duì)象的with上下文語(yǔ)法來(lái)進(jìn)行隱式的加鎖和解鎖操作。

方法二:使用元類(lèi)實(shí)現(xiàn)單例模式。

class SingletonMeta(type):"""自定義單例元類(lèi)"""def __init__(cls, *args, **kwargs):cls.__instance = Nonesuper().__init__(*args, **kwargs)def __call__(cls, *args, **kwargs):if cls.__instance is None:cls.__instance = super().__call__(*args, **kwargs)return cls.__instanceclass President(metaclass=SingletonMeta):pass

擴(kuò)展:Python是面向?qū)ο蟮木幊陶Z(yǔ)言,在面向?qū)ο蟮氖澜缰?#xff0c;一切皆為對(duì)象。對(duì)象是通過(guò)類(lèi)來(lái)創(chuàng)建的,而類(lèi)本身也是對(duì)象,類(lèi)這樣的對(duì)象是通過(guò)元類(lèi)來(lái)創(chuàng)建的。我們?cè)诙x類(lèi)時(shí),如果沒(méi)有給一個(gè)類(lèi)指定父類(lèi),那么默認(rèn)的父類(lèi)是object,如果沒(méi)有給一個(gè)類(lèi)指定元類(lèi),那么默認(rèn)的元類(lèi)是type。通過(guò)自定義的元類(lèi),我們可以改變一個(gè)類(lèi)默認(rèn)的行為,就如同上面的代碼中,我們通過(guò)元類(lèi)的__call__魔術(shù)方法,改變了President類(lèi)的構(gòu)造器那樣。

補(bǔ)充:關(guān)于單例模式,在面試中還有可能被問(wèn)到它的應(yīng)用場(chǎng)景。通常一個(gè)對(duì)象的狀態(tài)是被其他對(duì)象共享的,就可以將其設(shè)計(jì)為單例,例如項(xiàng)目中使用的數(shù)據(jù)庫(kù)連接池對(duì)象和配置對(duì)象通常都是單例,這樣才能保證所有地方獲取到的數(shù)據(jù)庫(kù)連接和配置信息是完全一致的;而且由于對(duì)象只有唯一的實(shí)例,因此從根本上避免了重復(fù)創(chuàng)建對(duì)象造成的時(shí)間和空間上的開(kāi)銷(xiāo),也避免了對(duì)資源的多重占用。再舉個(gè)例子,項(xiàng)目中的日志操作通常也會(huì)使用單例模式,這是因?yàn)楣蚕淼娜罩疚募恢碧幱诖蜷_(kāi)狀態(tài),只能有一個(gè)實(shí)例去操作它,否則在寫(xiě)入日志的時(shí)候會(huì)產(chǎn)生混亂。

題目002:不使用中間變量,交換兩個(gè)變量a和b的值。

點(diǎn)評(píng):典型的送人頭的題目,通常交換兩個(gè)變量需要借助一個(gè)中間變量,如果不允許使用中間變量,在其他編程語(yǔ)言中可以使用異或運(yùn)算的方式來(lái)實(shí)現(xiàn)交換兩個(gè)變量的值,但是Python中有更為簡(jiǎn)單明了的做法。

方法一:

a = a ^ b b = a ^ b a = a ^ b

方法二:

a, b = b, a

擴(kuò)展:需要注意,a, b = b, a這種做法其實(shí)并不是元組解包,雖然很多人都這樣認(rèn)為。Python字節(jié)碼指令中有ROT_TWO指令來(lái)支持這個(gè)操作,類(lèi)似的還有ROT_THREE,對(duì)于3個(gè)以上的元素,如a, b, c, d = b, c, d, a,才會(huì)用到創(chuàng)建元組和元組解包。想知道你的代碼對(duì)應(yīng)的字節(jié)碼指令,可以使用Python標(biāo)準(zhǔn)庫(kù)中dis模塊的dis函數(shù)來(lái)反匯編你的Python代碼。

題目003:寫(xiě)一個(gè)刪除列表中重復(fù)元素的函數(shù),要求去重后元素相對(duì)位置保持不變。

點(diǎn)評(píng):這個(gè)題目在初中級(jí)Python崗位面試的時(shí)候經(jīng)常出現(xiàn),題目源于《Python Cookbook》這本書(shū)第一章的第10個(gè)問(wèn)題,有很多面試題其實(shí)都是這本書(shū)上的原題,所以建議大家有時(shí)間好好研讀一下這本書(shū)。

def dedup(items):no_dup_items = []seen = set()for item in items:if item not in seen:no_dup_items.append(item)seen.add(item)return no_dup_items

如果愿意也可以把上面的函數(shù)改造成一個(gè)生成器,代碼如下所示。

def dedup(items):seen = set()for item in items:if item not in seen:yield itemseen.add(item)

擴(kuò)展:由于Python中的集合底層使用哈希存儲(chǔ),所以集合的in和not in成員運(yùn)算在性能上遠(yuǎn)遠(yuǎn)優(yōu)于列表,所以上面的代碼我們使用了集合來(lái)保存已經(jīng)出現(xiàn)過(guò)的元素。集合中的元素必須是hashable對(duì)象,因此上面的代碼在列表元素不是hashable對(duì)象時(shí)會(huì)失效,要解決這個(gè)問(wèn)題可以給函數(shù)增加一個(gè)參數(shù),該參數(shù)可以設(shè)計(jì)為返回哈希碼或hashable對(duì)象的函數(shù)。

題目004:假設(shè)你使用的是官方的CPython,說(shuō)出下面代碼的運(yùn)行結(jié)果。

點(diǎn)評(píng):下面的程序?qū)?shí)際開(kāi)發(fā)并沒(méi)有什么意義,但卻是CPython中的一個(gè)大坑,這道題旨在考察面試者對(duì)官方的Python解釋器到底了解到什么程度。

a, b, c, d = 1, 1, 1000, 1000 print(a is b, c is d)def foo():e = 1000f = 1000print(e is f, e is d)g = 1print(g is a)foo()

運(yùn)行結(jié)果:

True False True False True

上面代碼中a is b的結(jié)果是True但c is d的結(jié)果是False,這一點(diǎn)的確讓人費(fèi)解。CPython解釋器出于性能優(yōu)化的考慮,把頻繁使用的整數(shù)對(duì)象用一個(gè)叫small_ints的對(duì)象池緩存起來(lái)造成的。small_ints緩存的整數(shù)值被設(shè)定為[-5, 256]這個(gè)區(qū)間,也就是說(shuō),在任何引用這些整數(shù)的地方,都不需要重新創(chuàng)建int對(duì)象,而是直接引用緩存池中的對(duì)象。如果整數(shù)不在該范圍內(nèi),那么即便兩個(gè)整數(shù)的值相同,它們也是不同的對(duì)象。

CPython底層為了進(jìn)一步提升性能還做了另一個(gè)設(shè)定,對(duì)于同一個(gè)代碼塊中值不在small_ints緩存范圍內(nèi)的整數(shù),如果同一個(gè)代碼塊中已經(jīng)存在一個(gè)值與其相同的整數(shù)對(duì)象,那么就直接引用該對(duì)象,否則創(chuàng)建新的int對(duì)象。需要大家注意的是,這條規(guī)則對(duì)數(shù)值型適用,但對(duì)字符串則需要考慮字符串的長(zhǎng)度,這一點(diǎn)大家可以自行證明。

擴(kuò)展:如果你用PyPy(另一種Python解釋器實(shí)現(xiàn),支持JIT,對(duì)CPython的缺點(diǎn)進(jìn)行了改良,在性能上優(yōu)于CPython,但對(duì)三方庫(kù)的支持略差)來(lái)運(yùn)行上面的代碼,你會(huì)發(fā)現(xiàn)所有的輸出都是True。

題目005:Lambda函數(shù)是什么,舉例說(shuō)明的它的應(yīng)用場(chǎng)景。

點(diǎn)評(píng):這個(gè)題目主要想考察的是Lambda函數(shù)的應(yīng)用場(chǎng)景,潛臺(tái)詞是問(wèn)你在項(xiàng)目中有沒(méi)有使用過(guò)Lambda函數(shù),具體在什么場(chǎng)景下會(huì)用到Lambda函數(shù),借此來(lái)判斷你寫(xiě)代碼的能力。因?yàn)長(zhǎng)ambda函數(shù)通常用在高階函數(shù)中,主要的作用是通過(guò)向函數(shù)傳入函數(shù)或讓函數(shù)返回函數(shù)最終實(shí)現(xiàn)代碼的解耦合。

Lambda函數(shù)也叫匿名函數(shù),它是功能簡(jiǎn)單用一行代碼就能實(shí)現(xiàn)的小型函數(shù)。Python中的Lambda函數(shù)只能寫(xiě)一個(gè)表達(dá)式,這個(gè)表達(dá)式的執(zhí)行結(jié)果就是函數(shù)的返回值,不用寫(xiě)return關(guān)鍵字。Lambda函數(shù)因?yàn)闆](méi)有名字,所以也不會(huì)跟其他函數(shù)發(fā)生命名沖突的問(wèn)題。

擴(kuò)展:面試的時(shí)候有可能還會(huì)考你用Lambda函數(shù)來(lái)實(shí)現(xiàn)一些功能,也就是用一行代碼來(lái)實(shí)現(xiàn)題目要求的功能,例如:用一行代碼實(shí)現(xiàn)求階乘的函數(shù),用一行代碼實(shí)現(xiàn)求最大公約數(shù)的函數(shù)等。

fac = lambda x: __import__('functools').reduce(int.__mul__, range(1, x + 1), 1) gcd = lambda x, y: y % x and gcd(y % x, x) or x

Lambda函數(shù)其實(shí)最為主要的用途是把一個(gè)函數(shù)傳入另一個(gè)高階函數(shù)(如Python內(nèi)置的filter、map等)中來(lái)為函數(shù)做解耦合,增強(qiáng)函數(shù)的靈活性和通用性。下面的例子通過(guò)使用filter和map函數(shù),實(shí)現(xiàn)了從列表中篩選出奇數(shù)并求平方構(gòu)成新列表的操作,因?yàn)橛玫搅烁唠A函數(shù),過(guò)濾和映射數(shù)據(jù)的規(guī)則都是函數(shù)的調(diào)用者通過(guò)另外一個(gè)函數(shù)傳入的,因此這filter和map函數(shù)沒(méi)有跟特定的過(guò)濾和映射數(shù)據(jù)的規(guī)則耦合在一起。

items = [12, 5, 7, 10, 8, 19] items = list(map(lambda x: x ** 2, filter(lambda x: x % 2, items))) print(items) # [25, 49, 361]

擴(kuò)展:用列表的生成式來(lái)實(shí)現(xiàn)上面的代碼會(huì)更加簡(jiǎn)單明了,代碼如下所示。

items = [12, 5, 7, 10, 8, 19] items = [x ** 2 for x in items if x % 2] print(items) # [25, 49, 361]

題目006:說(shuō)說(shuō)Python中的淺拷貝和深拷貝。

點(diǎn)評(píng):這個(gè)題目本身出現(xiàn)的頻率非常高,但是就題論題而言沒(méi)有什么技術(shù)含量。對(duì)于這種面試題,在回答的時(shí)候一定要讓你的答案能夠超出面試官的預(yù)期,這樣才能獲得更好的印象分。所以回答這個(gè)題目的要點(diǎn)不僅僅是能夠說(shuō)出淺拷貝和深拷貝的區(qū)別,深拷貝的時(shí)候可能遇到的兩大問(wèn)題,還要說(shuō)出Python標(biāo)準(zhǔn)庫(kù)對(duì)淺拷貝和深拷貝的支持,然后可以說(shuō)說(shuō)列表、字典如何實(shí)現(xiàn)拷貝操作以及如何通過(guò)序列化和反序列的方式實(shí)現(xiàn)深拷貝,最后還可以提到設(shè)計(jì)模式中的原型模式以及它在項(xiàng)目中的應(yīng)用。

淺拷貝通常只復(fù)制對(duì)象本身,而深拷貝不僅會(huì)復(fù)制對(duì)象,還會(huì)遞歸的復(fù)制對(duì)象所關(guān)聯(lián)的對(duì)象。深拷貝可能會(huì)遇到兩個(gè)問(wèn)題:一是一個(gè)對(duì)象如果直接或間接的引用了自身,會(huì)導(dǎo)致無(wú)休止的遞歸拷貝;二是深拷貝可能對(duì)原本設(shè)計(jì)為多個(gè)對(duì)象共享的數(shù)據(jù)也進(jìn)行拷貝。Python通過(guò)copy模塊中的copy和deepcopy函數(shù)來(lái)實(shí)現(xiàn)淺拷貝和深拷貝操作,其中deepcopy可以通過(guò)memo字典來(lái)保存已經(jīng)拷貝過(guò)的對(duì)象,從而避免剛才所說(shuō)的自引用遞歸問(wèn)題;此外,可以通過(guò)copyreg模塊的pickle函數(shù)來(lái)定制指定類(lèi)型對(duì)象的拷貝行為。

deepcopy函數(shù)的本質(zhì)其實(shí)就是對(duì)象的一次序列化和一次返回序列化,面試題中還考過(guò)用自定義函數(shù)實(shí)現(xiàn)對(duì)象的深拷貝操作,顯然我們可以使用pickle模塊的dumps和loads來(lái)做到,代碼如下所示。

import picklemy_deep_copy = lambda obj: pickle.loads(pickle.dumps(obj))

列表的切片操作[:]相當(dāng)于實(shí)現(xiàn)了列表對(duì)象的淺拷貝,而字典的copy方法可以實(shí)現(xiàn)字典對(duì)象的淺拷貝。對(duì)象拷貝其實(shí)是更為快捷的創(chuàng)建對(duì)象的方式。在Python中,通過(guò)構(gòu)造器創(chuàng)建對(duì)象屬于兩階段構(gòu)造,首先是分配內(nèi)存空間,然后是初始化。在創(chuàng)建對(duì)象時(shí),我們也可以基于“原型”對(duì)象來(lái)創(chuàng)建新對(duì)象,通過(guò)對(duì)原型對(duì)象的拷貝(復(fù)制內(nèi)存)就完成了對(duì)象的創(chuàng)建和初始化,這種做法更加高效,這也就是設(shè)計(jì)模式中的原型模式。在Python中,我們可以通過(guò)元類(lèi)的方式來(lái)實(shí)現(xiàn)原型模式,代碼如下所示。

import copyclass PrototypeMeta(type):"""實(shí)現(xiàn)原型模式的元類(lèi)"""def __init__(cls, *args, **kwargs):super().__init__(*args, **kwargs)# 為對(duì)象綁定clone方法來(lái)實(shí)現(xiàn)對(duì)象拷貝cls.clone = lambda self, is_deep=True: \copy.deepcopy(self) if is_deep else copy.copy(self)class Person(metaclass=PrototypeMeta):passp1 = Person() p2 = p1.clone() # 深拷貝 p3 = p1.clone(is_deep=False) # 淺拷貝

題目007:Python是如何實(shí)現(xiàn)內(nèi)存管理的?

點(diǎn)評(píng):當(dāng)面試官問(wèn)到這個(gè)問(wèn)題的時(shí)候,一個(gè)展示自己的機(jī)會(huì)就擺在面前了。你要先反問(wèn)面試官:“你說(shuō)的是官方的CPython解釋器嗎?”。這個(gè)反問(wèn)可以展示出你了解過(guò)Python解釋器的不同的實(shí)現(xiàn)版本,而且你也知道面試官想問(wèn)的是CPython。當(dāng)然,很多面試官對(duì)不同的Python解釋器底層實(shí)現(xiàn)到底有什么差別也沒(méi)有概念。所以,千萬(wàn)不要覺(jué)得面試官一定比你強(qiáng),懷揣著這份自信可以讓你更好的完成面試。

Python提供了自動(dòng)化的內(nèi)存管理,也就是說(shuō)內(nèi)存空間的分配與釋放都是由Python解釋器在運(yùn)行時(shí)自動(dòng)進(jìn)行的,自動(dòng)管理內(nèi)存功能極大的減輕程序員的工作負(fù)擔(dān),也能夠幫助程序員在一定程度上解決內(nèi)存泄露的問(wèn)題。以CPython解釋器為例,它的內(nèi)存管理有三個(gè)關(guān)鍵點(diǎn):引用計(jì)數(shù)、標(biāo)記清理、分代收集。

引用計(jì)數(shù):對(duì)于CPython解釋器來(lái)說(shuō),Python中的每一個(gè)對(duì)象其實(shí)就是PyObject結(jié)構(gòu)體,它的內(nèi)部有一個(gè)名為ob_refcnt 的引用計(jì)數(shù)器成員變量。程序在運(yùn)行的過(guò)程中ob_refcnt的值會(huì)被更新并藉此來(lái)反映引用有多少個(gè)變量引用到該對(duì)象。當(dāng)對(duì)象的引用計(jì)數(shù)值為0時(shí),它的內(nèi)存就會(huì)被釋放掉。

typedef struct _object {_PyObject_HEAD_EXTRAPy_ssize_t ob_refcnt;struct _typeobject *ob_type; } PyObject;

以下情況會(huì)導(dǎo)致引用計(jì)數(shù)加1:

  • 對(duì)象被創(chuàng)建
  • 對(duì)象被引用
  • 對(duì)象作為參數(shù)傳入到一個(gè)函數(shù)中
  • 對(duì)象作為元素存儲(chǔ)到一個(gè)容器中

以下情況會(huì)導(dǎo)致引用計(jì)數(shù)減1:

  • 用del語(yǔ)句顯示刪除對(duì)象引用
  • 對(duì)象引用被重新賦值其他對(duì)象
  • 一個(gè)對(duì)象離開(kāi)它所在的作用域
  • 持有該對(duì)象的容器自身被銷(xiāo)毀
  • 持有該對(duì)象的容器刪除該對(duì)象

可以通過(guò)sys模塊的getrefcount函數(shù)來(lái)獲得對(duì)象的引用計(jì)數(shù)。引用計(jì)數(shù)的內(nèi)存管理方式在遇到循環(huán)引用的時(shí)候就會(huì)出現(xiàn)致命傷,因此需要其他的垃圾回收算法對(duì)其進(jìn)行補(bǔ)充。

標(biāo)記清理:CPython使用了“標(biāo)記-清理”(Mark and Sweep)算法解決容器類(lèi)型可能產(chǎn)生的循環(huán)引用問(wèn)題。該算法在垃圾回收時(shí)分為兩個(gè)階段:標(biāo)記階段,遍歷所有的對(duì)象,如果對(duì)象是可達(dá)的(被其他對(duì)象引用),那么就標(biāo)記該對(duì)象為可達(dá);清除階段,再次遍歷對(duì)象,如果發(fā)現(xiàn)某個(gè)對(duì)象沒(méi)有標(biāo)記為可達(dá),則就將其回收。CPython底層維護(hù)了兩個(gè)雙端鏈表,一個(gè)鏈表存放著需要被掃描的容器對(duì)象(姑且稱(chēng)之為鏈表A),另一個(gè)鏈表存放著臨時(shí)不可達(dá)對(duì)象(姑且稱(chēng)之為鏈表B)。為了實(shí)現(xiàn)“標(biāo)記-清理”算法,鏈表中的每個(gè)節(jié)點(diǎn)除了有記錄當(dāng)前引用計(jì)數(shù)的ref_count變量外,還有一個(gè)gc_ref變量,這個(gè)gc_ref是ref_count的一個(gè)副本,所以初始值為ref_count的大小。執(zhí)行垃圾回收時(shí),首先遍歷鏈表A中的節(jié)點(diǎn),并且將當(dāng)前對(duì)象所引用的所有對(duì)象的gc_ref減1,這一步主要作用是解除循環(huán)引用對(duì)引用計(jì)數(shù)的影響。再次遍歷鏈表A中的節(jié)點(diǎn),如果節(jié)點(diǎn)的gc_ref值為0,那么這個(gè)對(duì)象就被標(biāo)記為“暫時(shí)不可達(dá)”(GC_TENTATIVELY_UNREACHABLE)并被移動(dòng)到鏈表B中;如果節(jié)點(diǎn)的gc_ref不為0,那么這個(gè)對(duì)象就會(huì)被標(biāo)記為“可達(dá)“(GC_REACHABLE),對(duì)于”可達(dá)“對(duì)象,還要遞歸的將該節(jié)點(diǎn)可以到達(dá)的節(jié)點(diǎn)標(biāo)記為”可達(dá)“;鏈表B中被標(biāo)記為”可達(dá)“的節(jié)點(diǎn)要重新放回到鏈表A中。在兩次遍歷之后,鏈表B中的節(jié)點(diǎn)就是需要釋放內(nèi)存的節(jié)點(diǎn)。

分代回收:在循環(huán)引用對(duì)象的回收中,整個(gè)應(yīng)用程序會(huì)被暫停,為了減少應(yīng)用程序暫停的時(shí)間,Python 通過(guò)分代回收(空間換時(shí)間)的方法提高垃圾回收效率。分代回收的基本思想是:對(duì)象存在的時(shí)間越長(zhǎng),是垃圾的可能性就越小,應(yīng)該盡量不對(duì)這樣的對(duì)象進(jìn)行垃圾回收。CPython將對(duì)象分為三種世代分別記為0、1、2,每一個(gè)新生對(duì)象都在第0代中,如果該對(duì)象在一輪垃圾回收掃描中存活下來(lái),那么它將被移到第1代中,存在于第1代的對(duì)象將較少的被垃圾回收掃描到;如果在對(duì)第1代進(jìn)行垃圾回收掃描時(shí),這個(gè)對(duì)象又存活下來(lái),那么它將被移至第2代中,在那里它被垃圾回收掃描的次數(shù)將會(huì)更少。分代回收掃描的門(mén)限值可以通過(guò)gc模塊的get_threshold函數(shù)來(lái)獲得,該函數(shù)返回一個(gè)三元組,分別表示多少次內(nèi)存分配操作后會(huì)執(zhí)行0代垃圾回收,多少次0代垃圾回收后會(huì)執(zhí)行1代垃圾回收,多少次1代垃圾回收后會(huì)執(zhí)行2代垃圾回收。需要說(shuō)明的是,如果執(zhí)行一次2代垃圾回收,那么比它年輕的代都要執(zhí)行垃圾回收。如果想修改這幾個(gè)門(mén)限值,可以通過(guò)gc模塊的set_threshold函數(shù)來(lái)做到。

題目008:說(shuō)一下你對(duì)Python中迭代器和生成器的理解。

點(diǎn)評(píng):很多人面試者都會(huì)寫(xiě)迭代器和生成器,但是卻無(wú)法準(zhǔn)確的解釋什么是迭代器和生成器。如果你也有同樣的困惑,可以參考下面的回答。

迭代器是實(shí)現(xiàn)了迭代器協(xié)議的對(duì)象。跟其他編程語(yǔ)言不通,Python中沒(méi)有用于定義協(xié)議或表示約定的關(guān)鍵字,像interface、protocol這些單詞并不在Python語(yǔ)言的關(guān)鍵字列表中。Python語(yǔ)言通過(guò)魔法方法來(lái)表示約定,也就是我們所說(shuō)的協(xié)議,而__next__和__iter__這兩個(gè)魔法方法就代表了迭代器協(xié)議。可以通過(guò)for-in循環(huán)從迭代器對(duì)象中取出值,也可以使用next函數(shù)取出迭代器對(duì)象中的下一個(gè)值。生成器是迭代器的語(yǔ)法升級(jí)版本,可以用更為簡(jiǎn)單的代碼來(lái)實(shí)現(xiàn)一個(gè)迭代器。

擴(kuò)展:面試中經(jīng)常讓寫(xiě)生成斐波那契數(shù)列的迭代器,大家可以參考下面的代碼。

class Fib(object):def __init__(self, num):self.num = numself.a, self.b = 0, 1self.idx = 0def __iter__(self):return selfdef __next__(self):if self.idx < self.num:self.a, self.b = self.b, self.a + self.bself.idx += 1return self.araise StopIteration()

如果用生成器的語(yǔ)法來(lái)改寫(xiě)上面的代碼,代碼會(huì)簡(jiǎn)單優(yōu)雅很多。

def fib(num):a, b = 0, 1for _ in range(num):a, b = b, a + byield a

題目009:正則表達(dá)式的match方法和search方法有什么區(qū)別?

點(diǎn)評(píng):正則表達(dá)式是字符串處理的重要工具,所以也是面試中經(jīng)常考察的知識(shí)點(diǎn)。在Python中,使用正則表達(dá)式有兩種方式,一種是直接調(diào)用re模塊中的函數(shù),傳入正則表達(dá)式和需要處理的字符串;一種是先通過(guò)re模塊的compile函數(shù)創(chuàng)建正則表達(dá)式對(duì)象,然后再通過(guò)對(duì)象調(diào)用方法并傳入需要處理的字符串。如果一個(gè)正則表達(dá)式被頻繁的使用,我們推薦用re.compile函數(shù)創(chuàng)建正則表達(dá)式對(duì)象,這樣會(huì)減少頻繁編譯同一個(gè)正則表達(dá)式所造成的開(kāi)銷(xiāo)

match方法是從字符串的起始位置進(jìn)行正則表達(dá)式匹配,返回Match對(duì)象或None。search方法會(huì)掃描整個(gè)字符串來(lái)找尋匹配的模式,同樣也是返回Match對(duì)象或None。

題目010:下面這段代碼的執(zhí)行結(jié)果是什么。

def multiply():return [lambda x: i * x for i in range(4)]print([m(100) for m in multiply()])

運(yùn)行結(jié)果:

[300, 300, 300, 300]

上面代碼的運(yùn)行結(jié)果很容易被誤判為[0, 100, 200, 300]。首先需要注意的是multiply函數(shù)用生成式語(yǔ)法返回了一個(gè)列表,列表中保存了4個(gè)Lambda函數(shù),這4個(gè)Lambda函數(shù)會(huì)返回傳入的參數(shù)乘以i的結(jié)果。需要注意的是這里有閉包(closure)現(xiàn)象,multiply函數(shù)中的局部變量i的生命周期被延展了,由于i最終的值是3,所以通過(guò)m(100)調(diào)列表中的Lambda函數(shù)時(shí)會(huì)返回300,而且4個(gè)調(diào)用都是如此。

如果想得到[0, 100, 200, 300]這個(gè)結(jié)果,可以按照下面幾種方式來(lái)修改multiply函數(shù)。

方法一:使用生成器,讓函數(shù)獲得i的當(dāng)前值。

def multiply():return (lambda x: i * x for i in range(4))print([m(100) for m in multiply()])

或者

def multiply():for i in range(4):yield lambda x: x * iprint([m(100) for m in multiply()])

方法二:使用偏函數(shù),徹底避開(kāi)閉包。

from functools import partial from operator import __mul__def multiply():return [partial(__mul__, i) for i in range(4)]print([m(100) for m in multiply()])

題目011:Python中為什么沒(méi)有函數(shù)重載?

點(diǎn)評(píng):C++、Java、C#等諸多編程語(yǔ)言都支持函數(shù)重載,所謂函數(shù)重載指的是在同一個(gè)作用域中有多個(gè)同名函數(shù),它們擁有不同的參數(shù)列表(參數(shù)個(gè)數(shù)不同或參數(shù)類(lèi)型不同或二者皆不同),可以相互區(qū)分。重載也是一種多態(tài)性,因?yàn)橥ǔJ窃诰幾g時(shí)通過(guò)參數(shù)的個(gè)數(shù)和類(lèi)型來(lái)確定到底調(diào)用哪個(gè)重載函數(shù),所以也被稱(chēng)為編譯時(shí)多態(tài)性或者叫前綁定。這個(gè)問(wèn)題的潛臺(tái)詞其實(shí)是問(wèn)面試者是否有其他編程語(yǔ)言的經(jīng)驗(yàn),是否理解Python是動(dòng)態(tài)類(lèi)型語(yǔ)言,是否知道Python中函數(shù)的可變參數(shù)、關(guān)鍵字參數(shù)這些概念。

首先Python是解釋型語(yǔ)言,函數(shù)重載現(xiàn)象通常出現(xiàn)在編譯型語(yǔ)言中。其次Python是動(dòng)態(tài)類(lèi)型語(yǔ)言,函數(shù)的參數(shù)沒(méi)有類(lèi)型約束,也就無(wú)法根據(jù)參數(shù)類(lèi)型來(lái)區(qū)分重載。再者Python中函數(shù)的參數(shù)可以有默認(rèn)值,可以使用可變參數(shù)和關(guān)鍵字參數(shù),因此即便沒(méi)有函數(shù)重載,也要可以讓一個(gè)函數(shù)根據(jù)調(diào)用者傳入的參數(shù)產(chǎn)生不同的行為。

題目012:用Python代碼實(shí)現(xiàn)Python內(nèi)置函數(shù)max。

點(diǎn)評(píng):這個(gè)題目看似簡(jiǎn)單,但實(shí)際上還是比較考察面試者的功底。因?yàn)镻ython內(nèi)置的max函數(shù)既可以傳入可迭代對(duì)象找出最大,又可以傳入兩個(gè)或多個(gè)參數(shù)找出最大;最為關(guān)鍵的是還可以通過(guò)命名關(guān)鍵字參數(shù)key來(lái)指定一個(gè)用于元素比較的函數(shù),還可以通過(guò)default命名關(guān)鍵字參數(shù)來(lái)指定當(dāng)可迭代對(duì)象為空時(shí)返回的默認(rèn)值。

下面的代碼僅供參考:

def my_max(*args, key=None, default=None):"""獲取可迭代對(duì)象中最大的元素或兩個(gè)及以上實(shí)參中最大的元素:param args: 一個(gè)可迭代對(duì)象或多個(gè)元素:param key: 提取用于元素比較的特征值的函數(shù),默認(rèn)為None:param default: 如果可迭代對(duì)象為空則返回該默認(rèn)值,如果沒(méi)有給默認(rèn)值則引發(fā)ValueError異常:return: 返回可迭代對(duì)象或多個(gè)元素中的最大元素"""if len(args) == 1 and len(args[0]) == 0:if default:return defaultelse:raise ValueError('max() arg is an empty sequence')items = args[0] if len(args) == 1 else argsmax_elem, max_value = items[0], items[0]if key:max_value = key(max_value)for item in items:value = itemif key:value = key(item)if value > max_value:max_elem, max_value = item, valuereturn max_elem

題目013:寫(xiě)一個(gè)函數(shù)統(tǒng)計(jì)傳入的列表中每個(gè)數(shù)字出現(xiàn)的次數(shù)并返回對(duì)應(yīng)的字典。

點(diǎn)評(píng):送人頭的題目,不解釋。

def count_letters(items):result = {}for item in items:if isinstance(item, (int, float)):result[item] = result.get(item, 0) + 1return result

也可以直接使用Python標(biāo)準(zhǔn)庫(kù)中collections模塊的Counter類(lèi)來(lái)解決這個(gè)問(wèn)題,Counter是dict的子類(lèi),它會(huì)將傳入的序列中的每個(gè)元素作為鍵,元素出現(xiàn)的次數(shù)作為值來(lái)構(gòu)造字典。

from collections import Counterdef count_letters(items):counter = Counter(items)return {key: value for key, value in counter.items() \if isinstance(key, (int, float))}

題目014:使用Python代碼實(shí)現(xiàn)遍歷一個(gè)文件夾的操作。

點(diǎn)評(píng):基本也是送人頭的題目,只要用過(guò)os模塊就應(yīng)該知道怎么做。

Python標(biāo)準(zhǔn)庫(kù)os模塊的walk函數(shù)提供了遍歷一個(gè)文件夾的功能,它返回一個(gè)生成器。

import osg = os.walk('/Users/Hao/Downloads/') for path, dir_list, file_list in g:for dir_name in dir_list:print(os.path.join(path, dir_name))for file_name in file_list:print(os.path.join(path, file_name))

說(shuō)明:os.path模塊提供了很多進(jìn)行路徑操作的工具函數(shù),在項(xiàng)目開(kāi)發(fā)中也是經(jīng)常會(huì)用到的。如果題目明確要求不能使用os.walk函數(shù),那么可以使用os.listdir函數(shù)來(lái)獲取指定目錄下的文件和文件夾,然后再通過(guò)循環(huán)遍歷用os.isdir函數(shù)判斷哪些是文件夾,對(duì)于文件夾可以通過(guò)遞歸調(diào)用進(jìn)行遍歷,這樣也可以實(shí)現(xiàn)遍歷一個(gè)文件夾的操作。

題目015:現(xiàn)有2元、3元、5元共三種面額的貨幣,如果需要找零99元,一共有多少種找零的方式?

點(diǎn)評(píng):還有一個(gè)非常類(lèi)似的題目:“一個(gè)小朋友走樓梯,一次可以走1個(gè)臺(tái)階、2個(gè)臺(tái)階或3個(gè)臺(tái)階,問(wèn)走完10個(gè)臺(tái)階一共有多少種走法?”,這兩個(gè)題目的思路是一樣,如果用遞歸函數(shù)來(lái)寫(xiě)的話(huà)非常簡(jiǎn)單。

from functools import lru_cache@lru_cache() def change_money(total):if total == 0:return 1if total < 0:return 0return change_money(total - 2) + change_money(total - 3) + \change_money(total - 5)

說(shuō)明:在上面的代碼中,我們用lru_cache裝飾器裝飾了遞歸函數(shù)change_money,如果不做這個(gè)優(yōu)化,上面代碼的漸近時(shí)間復(fù)雜度將會(huì)是O(3N)O(3^N)O(3N),而如果參數(shù)total的值是99,這個(gè)運(yùn)算量是非常巨大的。lru_cache裝飾器會(huì)緩存函數(shù)的執(zhí)行結(jié)果,這樣就可以減少重復(fù)運(yùn)算所造成的開(kāi)銷(xiāo),這是空間換時(shí)間的策略,也是動(dòng)態(tài)規(guī)劃的編程思想。

題目016:寫(xiě)一個(gè)函數(shù),給定矩陣的階數(shù)n,輸出一個(gè)螺旋式數(shù)字矩陣。

例如:n = 2,返回:

1 2 4 3

例如:n = 3,返回:

1 2 3 8 9 4 7 6 5

這個(gè)題目本身并不復(fù)雜,下面的代碼僅供參考。

def show_spiral_matrix(n):matrix = [[0] * n for _ in range(n)]row, col = 0, 0num, direction = 1, 0while num <= n ** 2:if matrix[row][col] == 0:matrix[row][col] = numnum += 1if direction == 0:if col < n - 1 and matrix[row][col + 1] == 0:col += 1else:direction += 1elif direction == 1:if row < n - 1 and matrix[row + 1][col] == 0:row += 1else:direction += 1elif direction == 2:if col > 0 and matrix[row][col - 1] == 0:col -= 1else:direction += 1else:if row > 0 and matrix[row - 1][col] == 0:row -= 1else:direction += 1direction %= 4for x in matrix:for y in x:print(y, end='\t')print()

題目017:閱讀下面的代碼,寫(xiě)出程序的運(yùn)行結(jié)果。

items = [1, 2, 3, 4] print([i for i in items if i > 2]) print([i for i in items if i % 2]) print([(x, y) for x, y in zip('abcd', (1, 2, 3, 4, 5))]) print({x: f'item{x ** 2}' for x in (2, 4, 6)}) print(len({x for x in 'hello world' if x not in 'abcdefg'}))

點(diǎn)評(píng)生成式(推導(dǎo)式)屬于Python的特色語(yǔ)法之一,幾乎是面試必考內(nèi)容。Python中通過(guò)生成式字面量語(yǔ)法,可以創(chuàng)建出列表、集合、字典。

[3, 4] [1, 3] [('a', 1), ('b', 2), ('c', 3), ('d', 4)] {2: 'item4', 4: 'item16', 6: 'item36'} 6

題目018:說(shuō)出下面代碼的運(yùn)行結(jié)果。

class Parent:x = 1class Child1(Parent):passclass Child2(Parent):passprint(Parent.x, Child1.x, Child2.x) Child1.x = 2 print(Parent.x, Child1.x, Child2.x) Parent.x = 3 print(Parent.x, Child1.x, Child2.x)

點(diǎn)評(píng):運(yùn)行上面的代碼首先輸出1 1 1,這一點(diǎn)大家應(yīng)該沒(méi)有什么疑問(wèn)。接下來(lái),通過(guò)Child1.x = 2給類(lèi)Child1重新綁定了屬性x并賦值為2,所以Child1.x會(huì)輸出2,而Parent和Child2并不受影響。執(zhí)行Parent.x = 3會(huì)重新給Parent類(lèi)的x屬性賦值為3,由于Child2的x屬性繼承自Parent,所以Child2.x的值也是3;而之前我們?yōu)镃hild1重新綁定了x屬性,那么它的x屬性值不會(huì)受到Parent.x = 3的影響,還是之前的值2。

1 1 1 1 2 1 3 2 3

題目19:說(shuō)說(shuō)你用過(guò)Python標(biāo)準(zhǔn)庫(kù)中的哪些模塊。

點(diǎn)評(píng):Python標(biāo)準(zhǔn)庫(kù)中的模塊非常多,建議大家根據(jù)自己過(guò)往的項(xiàng)目經(jīng)歷來(lái)介紹你用過(guò)的標(biāo)準(zhǔn)庫(kù)和三方庫(kù),因?yàn)檫@些是你最為熟悉的,經(jīng)得起面試官深挖的。

模塊名介紹
sys跟Python解釋器相關(guān)的變量和函數(shù),例如:sys.version、sys.exit()
os和操作系統(tǒng)相關(guān)的功能,例如:os.listdir()、os.remove()
re和正則表達(dá)式相關(guān)的功能,例如:re.compile()、re.search()
math和數(shù)學(xué)運(yùn)算相關(guān)的功能,例如:math.pi、math.e、math.cos
logging和日志系統(tǒng)相關(guān)的類(lèi)和函數(shù),例如:logging.Logger、logging.Handler
json / pickle實(shí)現(xiàn)對(duì)象序列化和反序列的模塊,例如:json.loads、json.dumps
hashlib封裝了多種哈希摘要算法的模塊,例如:hashlib.md5、hashlib.sha1
urllib包含了和URL相關(guān)的子模塊,例如:urllib.request、urllib.parse
itertools提供各種迭代器的模塊,例如:itertools.cycle、itertools.product
functools函數(shù)相關(guān)工具模塊,例如:functools.partial、functools.lru_cache
collections / heapq封裝了常用數(shù)據(jù)結(jié)構(gòu)和算法的模塊,例如:collections.deque
threading / multiprocessing多線(xiàn)程/多進(jìn)程相關(guān)類(lèi)和函數(shù)的模塊,例如:threading.Thread
concurrent.futures / asyncio并發(fā)編程/異步編程相關(guān)的類(lèi)和函數(shù)的模塊,例如:ThreadPoolExecutor
base64提供BASE-64編碼相關(guān)函數(shù)的模塊,例如:bas64.encode
csv和讀寫(xiě)CSV文件相關(guān)的模塊,例如:csv.reader、csv.writer
profile / cProfile / pstats和代碼性能剖析相關(guān)的模塊,例如:cProfile.run、pstats.Stats
unittest和單元測(cè)試相關(guān)的模塊,例如:unittest.TestCase

題目20:__init__和__new__方法有什么區(qū)別?

Python中調(diào)用構(gòu)造器創(chuàng)建對(duì)象屬于兩階段構(gòu)造過(guò)程,首先執(zhí)行__new__方法獲得保存對(duì)象所需的內(nèi)存空間,再通過(guò)__init__執(zhí)行對(duì)內(nèi)存空間數(shù)據(jù)的填充(對(duì)象屬性的初始化)。__new__方法的返回值是創(chuàng)建好的Python對(duì)象(的引用),而__init__方法的第一個(gè)參數(shù)就是這個(gè)對(duì)象(的引用),所以在__init__中可以完成對(duì)對(duì)象的初始化操作。__new__是類(lèi)方法,它的第一個(gè)參數(shù)是類(lèi),__init__是對(duì)象方法,它的第一個(gè)參數(shù)是對(duì)象。

題目21:輸入年月日,判斷這個(gè)日期是這一年的第幾天。

方法一:不使用標(biāo)準(zhǔn)庫(kù)中的模塊和函數(shù)。

def is_leap_year(year):"""判斷指定的年份是不是閏年,平年返回False,閏年返回True"""return year % 4 == 0 and year % 100 != 0 or year % 400 == 0def which_day(year, month, date):"""計(jì)算傳入的日期是這一年的第幾天"""# 用嵌套的列表保存平年和閏年每個(gè)月的天數(shù)days_of_month = [[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],[31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]]days = days_of_month[is_leap_year(year)][:month - 1]return sum(days) + date

方法二:使用標(biāo)準(zhǔn)庫(kù)中的datetime模塊。

import datetimedef which_day(year, month, date):end = datetime.date(year, month, date)start = datetime.date(year, 1, 1)return (end - start).days + 1

題目22:平常工作中用什么工具進(jìn)行靜態(tài)代碼分析。

點(diǎn)評(píng):靜態(tài)代碼分析工具可以從代碼中提煉出各種靜態(tài)屬性,這使得開(kāi)發(fā)者可以對(duì)代碼的復(fù)雜性、可維護(hù)性和可讀性有更好的了解,這里所說(shuō)的靜態(tài)屬性包括:

  • 代碼是否符合編碼規(guī)范,例如:PEP-8。
  • 代碼中潛在的問(wèn)題,包括:語(yǔ)法錯(cuò)誤、縮進(jìn)問(wèn)題、導(dǎo)入缺失、變量覆蓋等。
  • 代碼中的壞味道。
  • 代碼的復(fù)雜度。
  • 代碼的邏輯問(wèn)題。
  • 工作中靜態(tài)代碼分析主要用到的是Pylint和Flake8。Pylint可以檢查出代碼錯(cuò)誤、壞味道、不規(guī)范的代碼等問(wèn)題,較新的版本中還提供了代碼復(fù)雜度統(tǒng)計(jì)數(shù)據(jù),可以生成檢查報(bào)告。Flake8封裝了Pyflakes(檢查代碼邏輯錯(cuò)誤)、McCabe(檢查代碼復(fù)雜性)和Pycodestyle(檢查代碼是否符合PEP-8規(guī)范)工具,它可以執(zhí)行這三個(gè)工具提供的檢查。

    題目23:說(shuō)一下你知道的Python中的魔術(shù)方法。

    點(diǎn)評(píng):魔術(shù)方法也稱(chēng)為魔法方法,是Python中的特色語(yǔ)法,也是面試中的高頻問(wèn)題。

    魔術(shù)方法作用
    __new__、__init__、__del__創(chuàng)建和銷(xiāo)毀對(duì)象相關(guān)
    __add__、__sub__、__mul__、__div__、__floordiv__、__mod__算術(shù)運(yùn)算符相關(guān)
    __eq__、__ne__、__lt__、__gt__、__le__、__ge__關(guān)系運(yùn)算符相關(guān)
    __pos__、__neg__、__invert__一元運(yùn)算符相關(guān)
    __lshift__、__rshift__、__and__、__or__、__xor__位運(yùn)算相關(guān)
    __enter__、__exit__上下文管理器協(xié)議
    __iter__、__next__、__reversed__迭代器協(xié)議
    __int__、__long__、__float__、__oct__、__hex__類(lèi)型/進(jìn)制轉(zhuǎn)換相關(guān)
    __str__、__repr__、__hash__、__dir__對(duì)象表述相關(guān)
    __len__、__getitem__、__setitem__、__contains__、__missing__序列相關(guān)
    __copy__、__deepcopy__對(duì)象拷貝相關(guān)
    __call__、__setattr__、__getattr__、__delattr__其他魔術(shù)方法

    題目24:函數(shù)參數(shù)*arg和**kwargs分別代表什么?

    Python中,函數(shù)的參數(shù)分為位置參數(shù)、可變參數(shù)、關(guān)鍵字參數(shù)、命名關(guān)鍵字參數(shù)。*args代表可變參數(shù),可以接收0個(gè)或任意多個(gè)參數(shù),當(dāng)不確定調(diào)用者會(huì)傳入多少個(gè)位置參數(shù)時(shí),就可以使用可變參數(shù),它會(huì)將傳入的參數(shù)打包成一個(gè)元組。**kwargs代表關(guān)鍵字參數(shù),可以接收用參數(shù)名=參數(shù)值的方式傳入的參數(shù),傳入的參數(shù)的會(huì)打包成一個(gè)字典。定義函數(shù)時(shí)如果同時(shí)使用*args和**kwargs,那么函數(shù)可以接收任意參數(shù)。

    題目25:寫(xiě)一個(gè)記錄函數(shù)執(zhí)行時(shí)間的裝飾器。

    點(diǎn)評(píng):高頻面試題,也是最簡(jiǎn)單的裝飾器,面試者必須要掌握的內(nèi)容

    方法一:用函數(shù)實(shí)現(xiàn)裝飾器。

    from functools import wraps from time import timedef record_time(func):@wraps(func)def wrapper(*args, **kwargs):start = time()result = func(*args, **kwargs)print(f'{func.__name__}執(zhí)行時(shí)間: {time() - start}秒')return resultreturn wrapper

    方法二:用類(lèi)實(shí)現(xiàn)裝飾器。類(lèi)有__call__魔術(shù)方法,該類(lèi)對(duì)象就是可調(diào)用對(duì)象,可以當(dāng)做裝飾器來(lái)使用。

    from functools import wraps from time import timeclass Record:def __call__(self, func):@wraps(func)def wrapper(*args, **kwargs):start = time()result = func(*args, **kwargs)print(f'{func.__name__}執(zhí)行時(shí)間: {time() - start}秒')return resultreturn wrapper

    說(shuō)明:裝飾器可以用來(lái)裝飾類(lèi)或函數(shù),為其提供額外的能力,屬于設(shè)計(jì)模式中的代理模式

    擴(kuò)展裝飾器本身也可以參數(shù)化,例如上面的例子中,如果不希望在終端中顯示函數(shù)的執(zhí)行時(shí)間而是希望由調(diào)用者來(lái)決定如何輸出函數(shù)的執(zhí)行時(shí)間,可以通過(guò)參數(shù)化裝飾器的方式來(lái)做到,代碼如下所示。

    from functools import wraps from time import timedef record_time(output):"""可以參數(shù)化的裝飾器"""def decorate(func):@wraps(func)def wrapper(*args, **kwargs):start = time()result = func(*args, **kwargs)output(func.__name__, time() - start)return resultreturn wrapperreturn decorate

    題目26:什么是鴨子類(lèi)型(duck typing)?

    鴨子類(lèi)型是動(dòng)態(tài)類(lèi)型語(yǔ)言判斷一個(gè)對(duì)象是不是某種類(lèi)型時(shí)使用的方法,也叫做鴨子判定法。簡(jiǎn)單的說(shuō),鴨子類(lèi)型是指判斷一只鳥(niǎo)是不是鴨子,我們只關(guān)心它游泳像不像鴨子、叫起來(lái)像不像鴨子、走路像不像鴨子就足夠了。換言之,如果對(duì)象的行為跟我們的預(yù)期是一致的(能夠接受某些消息),我們就認(rèn)定它是某種類(lèi)型的對(duì)象。

    在Python語(yǔ)言中,有很多bytes-like對(duì)象(如:bytes、bytearray、array.array、memoryview)、file-like對(duì)象(如:StringIO、BytesIO、GzipFile、socket)、path-like對(duì)象(如:str、bytes),其中file-like對(duì)象都能支持read和write操作,可以像文件一樣讀寫(xiě),這就是所謂的對(duì)象有鴨子的行為就可以判定為鴨子的判定方法。再比如Python中列表的extend方法,它需要的參數(shù)并不一定要是列表,只要是可迭代對(duì)象就沒(méi)有問(wèn)題。

    說(shuō)明:動(dòng)態(tài)語(yǔ)言的鴨子類(lèi)型使得設(shè)計(jì)模式的應(yīng)用被大大簡(jiǎn)化。

    題目27:說(shuō)一下Python中變量的作用域。

    Python中有四種作用域,分別是局部作用域(Local)、嵌套作用域(Embedded)、全局作用域(Global)、內(nèi)置作用域(Built-in),搜索一個(gè)標(biāo)識(shí)符時(shí),會(huì)按照LEGB的順序進(jìn)行搜索,如果所有的作用域中都沒(méi)有找到這個(gè)標(biāo)識(shí)符,就會(huì)引發(fā)NameError異常。

    題目28:說(shuō)一下你對(duì)閉包的理解。

    閉包是支持一等函數(shù)的編程語(yǔ)言(Python、JavaScript等)中實(shí)現(xiàn)詞法綁定的一種技術(shù)。當(dāng)捕捉閉包的時(shí)候,它的自由變量(在函數(shù)外部定義但在函數(shù)內(nèi)部使用的變量)會(huì)在捕捉時(shí)被確定,這樣即便脫離了捕捉時(shí)的上下文,它也能照常運(yùn)行。簡(jiǎn)單的說(shuō),可以將閉包理解為能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)。正在情況下,函數(shù)的局部變量在函數(shù)調(diào)用結(jié)束之后就結(jié)束了生命周期,但是閉包使得局部變量的生命周期得到了延展。使用閉包的時(shí)候需要注意,閉包會(huì)使得函數(shù)中創(chuàng)建的對(duì)象不會(huì)被垃圾回收,可能會(huì)導(dǎo)致很大的內(nèi)存開(kāi)銷(xiāo),所以閉包一定不能濫用

    題目29:說(shuō)一下Python中的多線(xiàn)程和多進(jìn)程的應(yīng)用場(chǎng)景和優(yōu)缺點(diǎn)。

    線(xiàn)程是操作系統(tǒng)分配CPU的基本單位,進(jìn)程是操作系統(tǒng)分配內(nèi)存的基本單位。通常我們運(yùn)行的程序會(huì)包含一個(gè)或多個(gè)進(jìn)程,而每個(gè)進(jìn)程中又包含一個(gè)或多個(gè)線(xiàn)程。多線(xiàn)程的優(yōu)點(diǎn)在于多個(gè)線(xiàn)程可以共享進(jìn)程的內(nèi)存空間,所以進(jìn)程間的通信非常容易實(shí)現(xiàn);但是如果使用官方的CPython解釋器,多線(xiàn)程受制于GIL(全局解釋器鎖),并不能利用CPU的多核特性,這是一個(gè)很大的問(wèn)題。使用多進(jìn)程可以充分利用CPU的多核特性,但是進(jìn)程間通信相對(duì)比較麻煩,需要使用IPC機(jī)制(管道、套接字等)。

    多線(xiàn)程適合那些會(huì)花費(fèi)大量時(shí)間在I/O操作上,但沒(méi)有太多并行計(jì)算需求且不需占用太多內(nèi)存的I/O密集型應(yīng)用。多進(jìn)程適合執(zhí)行計(jì)算密集型任務(wù)(如:視頻編碼解碼、數(shù)據(jù)處理、科學(xué)計(jì)算等)、可以分解為多個(gè)并行子任務(wù)并能合并子任務(wù)執(zhí)行結(jié)果的任務(wù)以及在內(nèi)存使用方面沒(méi)有任何限制且不強(qiáng)依賴(lài)于I/O操作的任務(wù)。

    擴(kuò)展:Python中實(shí)現(xiàn)并發(fā)編程通常有多線(xiàn)程、多進(jìn)程和異步編程三種選擇。異步編程實(shí)現(xiàn)了協(xié)作式并發(fā),通過(guò)多個(gè)相互協(xié)作的子程序的用戶(hù)態(tài)切換,實(shí)現(xiàn)對(duì)CPU的高效利用,這種方式也是非常適合I/O密集型應(yīng)用的。

    題目30:說(shuō)一下Python 2和Python 3的區(qū)別。

    點(diǎn)評(píng):這種問(wèn)題千萬(wàn)不要背所謂的參考答案,說(shuō)一些自己最熟悉的就足夠了。

  • Python 2中的print和exec都是關(guān)鍵字,在Python 3中變成了函數(shù)。
  • Python 3中沒(méi)有l(wèi)ong類(lèi)型,整數(shù)都是int類(lèi)型。
  • Python 2中的不等號(hào)<>在Python 3中被廢棄,統(tǒng)一使用!=。
  • Python 2中的xrange函數(shù)在Python 3中被range函數(shù)取代。
  • Python 3對(duì)Python 2中不安全的input函數(shù)做出了改進(jìn),廢棄了raw_input函數(shù)。
  • Python 2中的file函數(shù)被Python 3中的open函數(shù)取代。
  • Python 2中的/運(yùn)算對(duì)于int類(lèi)型是整除,在Python 3中要用//來(lái)做整除除法。
  • Python 3中改進(jìn)了Python 2捕獲異常的代碼,很明顯Python 3的寫(xiě)法更合理。
  • Python 3生成式中循環(huán)變量的作用域得到了更好的控制,不會(huì)影響到生成式之外的同名變量。
  • Python 3中的round函數(shù)可以返回int或float類(lèi)型,Python 2中的round函數(shù)返回float類(lèi)型。
  • Python 3的str類(lèi)型是Unicode字符串,Python 2的str類(lèi)型是字節(jié)串,相當(dāng)于Python 3中的bytes。
  • Python 3中的比較運(yùn)算符必須比較同類(lèi)對(duì)象。
  • Python 3中定義類(lèi)的都是新式類(lèi),Python 2中定義的類(lèi)有新式類(lèi)(顯式繼承自object的類(lèi))和舊式類(lèi)(經(jīng)典類(lèi))之分,新式類(lèi)和舊式類(lèi)在MRO問(wèn)題上有非常顯著的區(qū)別,新式類(lèi)可以使用__class__屬性獲取自身類(lèi)型,新式類(lèi)可以使用__slots__魔法。
  • Python 3對(duì)代碼縮進(jìn)的要求更加嚴(yán)格,如果混用空格和制表鍵會(huì)引發(fā)TabError。
  • Python 3中字典的keys、values、items方法都不再返回list對(duì)象,而是返回view object,內(nèi)置的map、filter等函數(shù)也不再返回list對(duì)象,而是返回迭代器對(duì)象。
  • Python 3標(biāo)準(zhǔn)庫(kù)中某些模塊的名字跟Python 2是有區(qū)別的;而在三方庫(kù)方面,有些三方庫(kù)只支持Python 2,有些只能支持Python 3。
  • 題目31:談?wù)勀銓?duì)“猴子補(bǔ)丁”(monkey patching)的理解。

    “猴子補(bǔ)丁”是動(dòng)態(tài)類(lèi)型語(yǔ)言的一個(gè)特性,代碼運(yùn)行時(shí)在不修改源代碼的前提下改變代碼中的方法、屬性、函數(shù)等以達(dá)到熱補(bǔ)丁(hot patch)的效果。很多系統(tǒng)的安全補(bǔ)丁也是通過(guò)猴子補(bǔ)丁的方式來(lái)實(shí)現(xiàn)的,但實(shí)際開(kāi)發(fā)中應(yīng)該避免對(duì)猴子補(bǔ)丁的使用,以免造成代碼行為不一致的問(wèn)題。

    在使用gevent庫(kù)的時(shí)候,我們會(huì)在代碼開(kāi)頭的地方執(zhí)行g(shù)event.monkey.patch_all(),這行代碼的作用是把標(biāo)準(zhǔn)庫(kù)中的socket模塊給替換掉,這樣我們?cè)谑褂胹ocket的時(shí)候,不用修改任何代碼就可以實(shí)現(xiàn)對(duì)代碼的協(xié)程化,達(dá)到提升性能的目的,這就是對(duì)猴子補(bǔ)丁的應(yīng)用。

    另外,如果希望用ujson三方庫(kù)替換掉標(biāo)準(zhǔn)庫(kù)中的json,也可以使用猴子補(bǔ)丁的方式,代碼如下所示。

    import json, ujsonjson.__name__ = 'ujson' json.dumps = ujson.dumps json.loads = ujson.loads

    單元測(cè)試中的Mock技術(shù)也是對(duì)猴子補(bǔ)丁的應(yīng)用,Python中的unittest.mock模塊就是解決單元測(cè)試中用Mock對(duì)象替代被測(cè)對(duì)象所依賴(lài)的對(duì)象的模塊。

    題目32:閱讀下面的代碼說(shuō)出運(yùn)行結(jié)果。

    class A:def who(self):print('A', end='')class B(A):def who(self):super(B, self).who()print('B', end='')class C(A):def who(self):super(C, self).who()print('C', end='')class D(B, C):def who(self):super(D, self).who()print('D', end='')item = D() item.who()

    點(diǎn)評(píng):這道題考查到了兩個(gè)知識(shí)點(diǎn):

  • Python中的MRO(方法解析順序)。在沒(méi)有多重繼承的情況下,向?qū)ο蟀l(fā)出一個(gè)消息,如果對(duì)象沒(méi)有對(duì)應(yīng)的方法,那么向上(父類(lèi))搜索的順序是非常清晰的。如果向上追溯到object類(lèi)(所有類(lèi)的父類(lèi))都沒(méi)有找到對(duì)應(yīng)的方法,那么將會(huì)引發(fā)AttributeError異常。但是有多重繼承尤其是出現(xiàn)菱形繼承(鉆石繼承)的時(shí)候,向上追溯到底應(yīng)該找到那個(gè)方法就得確定MRO。Python 3中的類(lèi)以及Python 2中的新式類(lèi)使用C3算法來(lái)確定MRO,它是一種類(lèi)似于廣度優(yōu)先搜索的方法;Python 2中的舊式類(lèi)(經(jīng)典類(lèi))使用深度優(yōu)先搜索來(lái)確定MRO。在搞不清楚MRO的情況下,可以使用類(lèi)的mro方法或__mro__屬性來(lái)獲得類(lèi)的MRO列表。
  • super()函數(shù)的使用。在使用super函數(shù)時(shí),可以通過(guò)super(類(lèi)型, 對(duì)象)來(lái)指定對(duì)哪個(gè)對(duì)象以哪個(gè)類(lèi)為起點(diǎn)向上搜索父類(lèi)方法。所以上面B類(lèi)代碼中的super(B, self).who()表示以B類(lèi)為起點(diǎn),向上搜索self(D類(lèi)對(duì)象)的who方法,所以會(huì)找到C類(lèi)中的who方法,因?yàn)镈類(lèi)對(duì)象的MRO列表是D --> B --> C --> A --> object。
  • ACBD

    題目33:編寫(xiě)一個(gè)函數(shù)實(shí)現(xiàn)對(duì)逆波蘭表達(dá)式求值,不能使用Python的內(nèi)置函數(shù)。

    點(diǎn)評(píng):逆波蘭表達(dá)式也稱(chēng)為“后綴表達(dá)式”,相較于平常我們使用的“中綴表達(dá)式”,逆波蘭表達(dá)式不需要括號(hào)來(lái)確定運(yùn)算的優(yōu)先級(jí),例如5 * (2 + 3)對(duì)應(yīng)的逆波蘭表達(dá)式是5 2 3 + *。逆波蘭表達(dá)式求值需要借助棧結(jié)構(gòu),掃描表達(dá)式遇到運(yùn)算數(shù)就入棧,遇到運(yùn)算符就出棧兩個(gè)元素做運(yùn)算,將運(yùn)算結(jié)果入棧。表達(dá)式掃描結(jié)束后,棧中只有一個(gè)數(shù),這個(gè)數(shù)就是最終的運(yùn)算結(jié)果,直接出棧即可。

    import operatorclass Stack:"""棧(FILO)"""def __init__(self):self.elems = []def push(self, elem):"""入棧"""self.elems.append(elem)def pop(self):"""出棧"""return self.elems.pop()@propertydef is_empty(self):"""檢查棧是否為空"""return len(self.elems) == 0def eval_suffix(expr):"""逆波蘭表達(dá)式求值"""operators = {'+': operator.add,'-': operator.sub,'*': operator.mul,'/': operator.truediv}stack = Stack()for item in expr.split():if item.isdigit():stack.push(float(item))else: num2 = stack.pop()num1 = stack.pop()stack.push(operators[item](num1, num2))return stack.pop()

    題目34:Python中如何實(shí)現(xiàn)字符串替換操作?

    Python中實(shí)現(xiàn)字符串替換大致有兩類(lèi)方法:字符串的replace方法和正則表達(dá)式的sub方法。

    方法一:使用字符串的replace方法。

    message = 'hello, world!' print(message.replace('o', 'O').replace('l', 'L').replace('he', 'HE'))

    方法二:使用正則表達(dá)式的sub方法。

    import remessage = 'hello, world!' pattern = re.compile('[aeiou]') print(pattern.sub('#', message))

    擴(kuò)展:還有一個(gè)相關(guān)的面試題,對(duì)保存文件名的列表排序,要求文件名按照字母表和數(shù)字大小進(jìn)行排序,例如對(duì)于列表filenames = ['a12.txt', 'a8.txt', 'b10.txt', 'b2.txt', 'b19.txt', 'a3.txt'],排序的結(jié)果是['a3.txt', 'a8.txt', 'a12.txt', 'b2.txt', 'b10.txt', 'b19.txt']。提示一下,可以通過(guò)字符串替換的方式為文件名補(bǔ)位,根據(jù)補(bǔ)位后的文件名用sorted函數(shù)來(lái)排序,大家可以思考下這個(gè)問(wèn)題如何解決。

    題目35:如何剖析Python代碼的執(zhí)行性能?

    剖析代碼性能可以使用Python標(biāo)準(zhǔn)庫(kù)中的cProfile和pstats模塊,cProfile的run函數(shù)可以執(zhí)行代碼并收集統(tǒng)計(jì)信息,創(chuàng)建出Stats對(duì)象并打印簡(jiǎn)單的剖析報(bào)告。Stats是pstats模塊中的類(lèi),它是一個(gè)統(tǒng)計(jì)對(duì)象。當(dāng)然,也可以使用三方工具line_profiler和memory_profiler來(lái)剖析每一行代碼耗費(fèi)的時(shí)間和內(nèi)存,這兩個(gè)三方工具都會(huì)用非常友好的方式輸出剖析結(jié)構(gòu)。如果使用PyCharm,可以利用“Run”菜單的“Profile”菜單項(xiàng)對(duì)代碼進(jìn)行性能分析,PyCharm中可以用表格或者調(diào)用圖(Call Graph)的方式來(lái)顯示性能剖析的結(jié)果。

    下面是使用cProfile剖析代碼性能的例子。

    example.py

    import cProfiledef is_prime(num):for factor in range(2, int(num ** 0.5) + 1):if num % factor == 0:return Falsereturn Trueclass PrimeIter:def __init__(self, total):self.counter = 0self.current = 1self.total = totaldef __iter__(self):return selfdef __next__(self):if self.counter < self.total:self.current += 1while not is_prime(self.current):self.current += 1self.counter += 1return self.currentraise StopIteration()cProfile.run('list(PrimeIter(10000))')

    如果使用line_profiler三方工具,可以直接剖析is_prime函數(shù)每行代碼的性能,需要給is_prime函數(shù)添加一個(gè)profiler裝飾器,代碼如下所示。

    @profiler def is_prime(num):for factor in range(2, int(num ** 0.5) + 1):if num % factor == 0:return Falsereturn True

    安裝line_profiler。

    pip install line_profiler

    使用line_profiler。

    kernprof -lv example.py

    運(yùn)行結(jié)果如下所示。

    Line # Hits Time Per Hit % Time Line Contents ==============================================================1 @profile2 def is_prime(num):3 86624 48420.0 0.6 50.5 for factor in range(2, int(num ** 0.5) + 1):4 85624 44000.0 0.5 45.9 if num % factor == 0:5 6918 3080.0 0.4 3.2 return False6 1000 430.0 0.4 0.4 return True

    題目36:如何使用random模塊生成隨機(jī)數(shù)、實(shí)現(xiàn)隨機(jī)亂序和隨機(jī)抽樣?

    點(diǎn)評(píng):送人頭的題目,因?yàn)镻ython標(biāo)準(zhǔn)庫(kù)中的常用模塊應(yīng)該是Python開(kāi)發(fā)者都比較熟悉的內(nèi)容,這個(gè)問(wèn)題回如果答不上來(lái),整個(gè)面試基本也就砸鍋了。

  • random.random()函數(shù)可以生成[0.0, 1.0)之間的隨機(jī)浮點(diǎn)數(shù)。
  • random.uniform(a, b)函數(shù)可以生成[a, b]或[b, a]之間的隨機(jī)浮點(diǎn)數(shù)。
  • random.randint(a, b)函數(shù)可以生成[a, b]或[b, a]之間的隨機(jī)整數(shù)。
  • random.shuffle(x)函數(shù)可以實(shí)現(xiàn)對(duì)序列x的原地隨機(jī)亂序。
  • random.choice(seq)函數(shù)可以從非空序列中取出一個(gè)隨機(jī)元素。
  • random.choices(population, weights=None, *, cum_weights=None, k=1)函數(shù)可以從總體中隨機(jī)抽取(有放回抽樣)出容量為k的樣本并返回樣本的列表,可以通過(guò)參數(shù)指定個(gè)體的權(quán)重,如果沒(méi)有指定權(quán)重,個(gè)體被選中的概率均等。
  • random.sample(population, k)函數(shù)可以從總體中隨機(jī)抽取(無(wú)放回抽樣)出容量為k的樣本并返回樣本的列表。
  • 擴(kuò)展:random模塊提供的函數(shù)除了生成均勻分布的隨機(jī)數(shù)外,還可以生成其他分布的隨機(jī)數(shù),例如random.gauss(mu, sigma)函數(shù)可以生成高斯分布(正態(tài)分布)的隨機(jī)數(shù);random.paretovariate(alpha)函數(shù)會(huì)生成帕累托分布的隨機(jī)數(shù);random.gammavariate(alpha, beta)函數(shù)會(huì)生成伽馬分布的隨機(jī)數(shù)。

    題目37:解釋一下線(xiàn)程池的工作原理。

    點(diǎn)評(píng):池化技術(shù)就是一種典型空間換時(shí)間的策略,我們使用的數(shù)據(jù)庫(kù)連接池、線(xiàn)程池等都是池化技術(shù)的應(yīng)用,Python標(biāo)準(zhǔn)庫(kù)currrent.futures模塊的ThreadPoolExecutor就是線(xiàn)程池的實(shí)現(xiàn),如果要弄清楚它的工作原理,可以參考下面的內(nèi)容。

    線(xiàn)程池是一種用于減少線(xiàn)程本身創(chuàng)建和銷(xiāo)毀造成的開(kāi)銷(xiāo)的技術(shù),屬于典型的空間換時(shí)間操作。如果應(yīng)用程序需要頻繁的將任務(wù)派發(fā)到線(xiàn)程中執(zhí)行,線(xiàn)程池就是必選項(xiàng),因?yàn)閯?chuàng)建和釋放線(xiàn)程涉及到大量的系統(tǒng)底層操作,開(kāi)銷(xiāo)較大,如果能夠在應(yīng)用程序工作期間,將創(chuàng)建和釋放線(xiàn)程的操作變成預(yù)創(chuàng)建和借還操作,將大大減少底層開(kāi)銷(xiāo)。線(xiàn)程池在應(yīng)用程序啟動(dòng)后,立即創(chuàng)建一定數(shù)量的線(xiàn)程,放入空閑隊(duì)列中。這些線(xiàn)程最開(kāi)始都處于阻塞狀態(tài),不會(huì)消耗CPU資源,但會(huì)占用少量的內(nèi)存空間。當(dāng)任務(wù)到來(lái)后,從隊(duì)列中取出一個(gè)空閑線(xiàn)程,把任務(wù)派發(fā)到這個(gè)線(xiàn)程中運(yùn)行,并將該線(xiàn)程標(biāo)記為已占用。當(dāng)線(xiàn)程池中所有的線(xiàn)程都被占用后,可以選擇自動(dòng)創(chuàng)建一定數(shù)量的新線(xiàn)程,用于處理更多的任務(wù),也可以選擇讓任務(wù)排隊(duì)等待直到有空閑的線(xiàn)程可用。在任務(wù)執(zhí)行完畢后,線(xiàn)程并不退出結(jié)束,而是繼續(xù)保持在池中等待下一次的任務(wù)。當(dāng)系統(tǒng)比較空閑時(shí),大部分線(xiàn)程長(zhǎng)時(shí)間處于閑置狀態(tài)時(shí),線(xiàn)程池可以自動(dòng)銷(xiāo)毀一部分線(xiàn)程,回收系統(tǒng)資源。基于這種預(yù)創(chuàng)建技術(shù),線(xiàn)程池將線(xiàn)程創(chuàng)建和銷(xiāo)毀本身所帶來(lái)的開(kāi)銷(xiāo)分?jǐn)偟搅烁鱾€(gè)具體的任務(wù)上,執(zhí)行次數(shù)越多,每個(gè)任務(wù)所分擔(dān)到的線(xiàn)程本身開(kāi)銷(xiāo)則越小。

    一般線(xiàn)程池都必須具備下面幾個(gè)組成部分:

  • 線(xiàn)程池管理器:用于創(chuàng)建并管理線(xiàn)程池。
  • 工作線(xiàn)程和線(xiàn)程隊(duì)列:線(xiàn)程池中實(shí)際執(zhí)行的線(xiàn)程以及保存這些線(xiàn)程的容器。
  • 任務(wù)接口:將線(xiàn)程執(zhí)行的任務(wù)抽象出來(lái),形成任務(wù)接口,確保線(xiàn)程池與具體的任務(wù)無(wú)關(guān)。
  • 任務(wù)隊(duì)列:線(xiàn)程池中保存等待被執(zhí)行的任務(wù)的容器。
  • 題目38:舉例說(shuō)明什么情況下會(huì)出現(xiàn)KeyError、TypeError、ValueError。

    舉一個(gè)簡(jiǎn)單的例子,變量a是一個(gè)字典,執(zhí)行int(a['x'])這個(gè)操作就有可能引發(fā)上述三種類(lèi)型的異常。如果字典中沒(méi)有鍵x,會(huì)引發(fā)KeyError;如果鍵x對(duì)應(yīng)的值不是str、float、int、bool以及bytes-like類(lèi)型,在調(diào)用int函數(shù)構(gòu)造int類(lèi)型的對(duì)象時(shí),會(huì)引發(fā)TypeError;如果a[x]是一個(gè)字符串或者字節(jié)串,而對(duì)應(yīng)的內(nèi)容又無(wú)法處理成int時(shí),將引發(fā)ValueError。

    題目39:說(shuō)出下面代碼的運(yùn)行結(jié)果。

    def extend_list(val, items=[]):items.append(val)return itemslist1 = extend_list(10) list2 = extend_list(123, []) list3 = extend_list('a') print(list1) print(list2) print(list3)

    點(diǎn)評(píng):Python函數(shù)在定義的時(shí)候,默認(rèn)參數(shù)items的值就被計(jì)算出來(lái)了,即[]。因?yàn)槟J(rèn)參數(shù)items引用了對(duì)象[],每次調(diào)用該函數(shù),如果對(duì)items引用的列表進(jìn)行了操作,下次調(diào)用時(shí),默認(rèn)參數(shù)還是引用之前的那個(gè)列表而不是重新賦值為[],所以列表中會(huì)有之前添加的元素。如果通過(guò)傳參的方式為items重新賦值,那么items將引用到新的列表對(duì)象,而不再引用默認(rèn)的那個(gè)列表對(duì)象。這個(gè)題在面試中經(jīng)常被問(wèn)到,通常不建議使用容器類(lèi)型的默認(rèn)參數(shù),像PyLint這樣的代碼檢查工具也會(huì)對(duì)這種代碼提出質(zhì)疑和警告。

    [10, 'a'] [123] [10, 'a']

    題目40:如何讀取大文件,例如內(nèi)存只有4G,如何讀取一個(gè)大小為8G的文件?

    很顯然4G內(nèi)存要一次性的加載大小為8G的文件是不現(xiàn)實(shí)的,遇到這種情況必須要考慮多次讀取和分批次處理。在Python中讀取文件可以先通過(guò)open函數(shù)獲取文件對(duì)象,在讀取文件時(shí),可以通過(guò)read方法的size參數(shù)指定讀取的大小,也可以通過(guò)seek方法的offset參數(shù)指定讀取的位置,這樣就可以控制單次讀取數(shù)據(jù)的字節(jié)數(shù)和總字節(jié)數(shù)。除此之外,可以使用內(nèi)置函數(shù)iter將文件對(duì)象處理成迭代器對(duì)象,每次只讀取少量的數(shù)據(jù)進(jìn)行處理,代碼大致寫(xiě)法如下所示。

    with open('...', 'rb') as file:for data in iter(lambda: file.read(2097152), b''):pass

    在Linux系統(tǒng)上,可以通過(guò)split命令將大文件切割為小片,然后通過(guò)讀取切割后的小文件對(duì)數(shù)據(jù)進(jìn)行處理。例如下面的命令將名為filename的大文件切割為大小為512M的多個(gè)文件。

    split -b 512m filename

    如果愿意, 也可以將名為filename的文件切割為10個(gè)文件,命令如下所示。

    split -n 10 filename

    擴(kuò)展:外部排序跟上述的情況非常類(lèi)似,由于處理的數(shù)據(jù)不能一次裝入內(nèi)存,只能放在讀寫(xiě)較慢的外存儲(chǔ)器(通常是硬盤(pán))上。“排序-歸并算法”就是一種常用的外部排序策略。在排序階段,先讀入能放在內(nèi)存中的數(shù)據(jù)量,將其排序輸出到一個(gè)臨時(shí)文件,依此進(jìn)行,將待排序數(shù)據(jù)組織為多個(gè)有序的臨時(shí)文件,然后在歸并階段將這些臨時(shí)文件組合為一個(gè)大的有序文件,這個(gè)大的有序文件就是排序的結(jié)果。

    題目41:說(shuō)一下你對(duì)Python中模塊和包的理解。

    每個(gè)Python文件就是一個(gè)模塊,而保存這些文件的文件夾就是一個(gè)包,但是這個(gè)作為Python包的文件夾必須要有一個(gè)名為_(kāi)_init__.py的文件,否則無(wú)法導(dǎo)入這個(gè)包。通常一個(gè)文件夾下還可以有子文件夾,這也就意味著一個(gè)包下還可以有子包,子包中的__init__.py并不是必須的。模塊和包解決了Python中命名沖突的問(wèn)題,不同的包下可以有同名的模塊,不同的模塊下可以有同名的變量、函數(shù)或類(lèi)。在Python中可以使用import或from ... import ...來(lái)導(dǎo)入包和模塊,在導(dǎo)入的時(shí)候還可以使用as關(guān)鍵字對(duì)包、模塊、類(lèi)、函數(shù)、變量等進(jìn)行別名,從而徹底解決編程中尤其是多人協(xié)作團(tuán)隊(duì)開(kāi)發(fā)時(shí)的命名沖突問(wèn)題。

    題目42:說(shuō)一下你知道的Python編碼規(guī)范。

    點(diǎn)評(píng):企業(yè)的Python編碼規(guī)范基本上是參照PEP-8或谷歌開(kāi)源項(xiàng)目風(fēng)格指南來(lái)制定的,后者還提到了可以使用Lint工具來(lái)檢查代碼的規(guī)范程度,面試的時(shí)候遇到這類(lèi)問(wèn)題,可以先說(shuō)下這兩個(gè)參照標(biāo)準(zhǔn),然后挑重點(diǎn)說(shuō)一下Python編碼的注意事項(xiàng)。

  • 空格的使用
    • 使用空格來(lái)表示縮進(jìn)而不要用制表符(Tab)。
    • 和語(yǔ)法相關(guān)的每一層縮進(jìn)都用4個(gè)空格來(lái)表示。
    • 每行的字符數(shù)不要超過(guò)79個(gè)字符,如果表達(dá)式因太長(zhǎng)而占據(jù)了多行,除了首行之外的其余各行都應(yīng)該在正常的縮進(jìn)寬度上再加上4個(gè)空格。
    • 函數(shù)和類(lèi)的定義,代碼前后都要用兩個(gè)空行進(jìn)行分隔。
    • 在同一個(gè)類(lèi)中,各個(gè)方法之間應(yīng)該用一個(gè)空行進(jìn)行分隔。
    • 二元運(yùn)算符的左右兩側(cè)應(yīng)該保留一個(gè)空格,而且只要一個(gè)空格就好。
  • 標(biāo)識(shí)符命名
    • 變量、函數(shù)和屬性應(yīng)該使用小寫(xiě)字母來(lái)拼寫(xiě),如果有多個(gè)單詞就使用下劃線(xiàn)進(jìn)行連接。
    • 類(lèi)中受保護(hù)的實(shí)例屬性,應(yīng)該以一個(gè)下劃線(xiàn)開(kāi)頭。
    • 類(lèi)中私有的實(shí)例屬性,應(yīng)該以?xún)蓚€(gè)下劃線(xiàn)開(kāi)頭。
    • 類(lèi)和異常的命名,應(yīng)該每個(gè)單詞首字母大寫(xiě)。
    • 模塊級(jí)別的常量,應(yīng)該采用全大寫(xiě)字母,如果有多個(gè)單詞就用下劃線(xiàn)進(jìn)行連接。
    • 類(lèi)的實(shí)例方法,應(yīng)該把第一個(gè)參數(shù)命名為self以表示對(duì)象自身。
    • 類(lèi)的類(lèi)方法,應(yīng)該把第一個(gè)參數(shù)命名為cls以表示該類(lèi)自身。
  • 表達(dá)式和語(yǔ)句
    • 采用內(nèi)聯(lián)形式的否定詞,而不要把否定詞放在整個(gè)表達(dá)式的前面。例如:if a is not b就比if not a is b更容易讓人理解。
    • 不要用檢查長(zhǎng)度的方式來(lái)判斷字符串、列表等是否為None或者沒(méi)有元素,應(yīng)該用if not x這樣的寫(xiě)法來(lái)檢查它。
    • 就算if分支、for循環(huán)、except異常捕獲等中只有一行代碼,也不要將代碼和if、for、except等寫(xiě)在一起,分開(kāi)寫(xiě)才會(huì)讓代碼更清晰。
    • import語(yǔ)句總是放在文件開(kāi)頭的地方。
    • 引入模塊的時(shí)候,from math import sqrt比import math更好。
    • 如果有多個(gè)import語(yǔ)句,應(yīng)該將其分為三部分,從上到下分別是Python標(biāo)準(zhǔn)模塊第三方模塊自定義模塊,每個(gè)部分內(nèi)部應(yīng)該按照模塊名稱(chēng)的字母表順序來(lái)排列。
  • 題目43:運(yùn)行下面的代碼是否會(huì)報(bào)錯(cuò),如果報(bào)錯(cuò)請(qǐng)說(shuō)明哪里有什么樣的錯(cuò),如果不報(bào)錯(cuò)請(qǐng)說(shuō)出代碼的執(zhí)行結(jié)果。

    class A: def __init__(self, value):self.__value = value@propertydef value(self):return self.__valueobj = A(1) obj.__value = 2 print(obj.value) print(obj.__value)

    點(diǎn)評(píng):這道題有兩個(gè)考察點(diǎn),一個(gè)考察點(diǎn)是對(duì)_和__開(kāi)頭的對(duì)象屬性訪(fǎng)問(wèn)權(quán)限以及@property裝飾器的了解,另外一個(gè)考察的點(diǎn)是對(duì)動(dòng)態(tài)語(yǔ)言的理解,不需要過(guò)多的解釋。

    1 2

    擴(kuò)展:如果不希望代碼運(yùn)行時(shí)動(dòng)態(tài)的給對(duì)象添加新屬性,可以在定義類(lèi)時(shí)使用__slots__魔法。例如,我們可以在上面的A中添加一行__slots__ = ('__value', ),再次運(yùn)行上面的代碼,將會(huì)在原來(lái)的第10行處產(chǎn)生AttributeError錯(cuò)誤。

    題目44:對(duì)下面給出的字典按值從大到小對(duì)鍵進(jìn)行排序。

    prices = {'AAPL': 191.88,'GOOG': 1186.96,'IBM': 149.24,'ORCL': 48.44,'ACN': 166.89,'FB': 208.09,'SYMC': 21.29 }

    點(diǎn)評(píng):sorted函數(shù)的高階用法在面試的時(shí)候經(jīng)常出現(xiàn),key參數(shù)可以傳入一個(gè)函數(shù)名或一個(gè)Lambda函數(shù),該函數(shù)的返回值代表了在排序時(shí)比較元素的依據(jù)。

    sorted(prices, key=lambda x: prices[x], reverse=True)

    題目45:說(shuō)一下namedtuple的用法和作用。

    點(diǎn)評(píng):Python標(biāo)準(zhǔn)庫(kù)的collections模塊提供了很多有用的數(shù)據(jù)結(jié)構(gòu),這些內(nèi)容并不是每個(gè)開(kāi)發(fā)者都清楚,就比如題目問(wèn)到的namedtuple,在我參加過(guò)的面試中,90%的面試者都不能準(zhǔn)確的說(shuō)出它的作用和應(yīng)用場(chǎng)景。此外,deque也是一個(gè)非常有用但又經(jīng)常被忽視的類(lèi),還有Counter、OrderedDict 、defaultdict 、UserDict等類(lèi),大家清楚它們的用法嗎?

    在使用面向?qū)ο缶幊陶Z(yǔ)言的時(shí)候,定義類(lèi)是最常見(jiàn)的一件事情,有的時(shí)候,我們會(huì)用到只有屬性沒(méi)有方法的類(lèi),這種類(lèi)的對(duì)象通常只用于組織數(shù)據(jù),并不能接收消息,所以我們把這種類(lèi)稱(chēng)為數(shù)據(jù)類(lèi)或者退化的類(lèi),就像C語(yǔ)言中的結(jié)構(gòu)體那樣。我們并不建議使用這種退化的類(lèi),在Python中可以用namedtuple(命名元組)來(lái)替代這種類(lèi)。

    from collections import namedtupleCard = namedtuple('Card', ('suite', 'face')) card1 = Card('紅桃', 13) card2 = Card('草花', 5) print(f'{card1.suite}{card1.face}') print(f'{card2.suite}{card2.face}')

    命名元組與普通元組一樣是不可變?nèi)萜?#xff0c;一旦將數(shù)據(jù)存儲(chǔ)在namedtuple的頂層屬性中,數(shù)據(jù)就不能再修改了,也就意味著對(duì)象上的所有屬性都遵循“一次寫(xiě)入,多次讀取”的原則。和普通元組不同的是,命名元組中的數(shù)據(jù)有訪(fǎng)問(wèn)名稱(chēng),可以通過(guò)名稱(chēng)而不是索引來(lái)獲取保存的數(shù)據(jù),不僅在操作上更加簡(jiǎn)單,代碼的可讀性也會(huì)更好。

    命名元組的本質(zhì)就是一個(gè)類(lèi),所以它還可以作為父類(lèi)創(chuàng)建子類(lèi)。除此之外,命名元組內(nèi)置了一系列的方法,例如,可以通過(guò)_asdict方法將命名元組處理成字典,也可以通過(guò)_replace方法創(chuàng)建命名元組對(duì)象的淺拷貝。

    class MyCard(Card):def show(self):faces = ['', 'A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']return f'{self.suite}{faces[self.face]}'print(Card) # <class '__main__.Card'> card3 = MyCard('方塊', 12) print(card3.show()) # 方塊Q print(dict(card1._asdict())) # {'suite': '紅桃', 'face': 13} print(card2._replace(suite='方塊')) # Card(suite='方塊', face=5)

    總而言之,命名元組能更好的組織數(shù)據(jù)結(jié)構(gòu),讓代碼更加清晰和可讀,在很多場(chǎng)景下是元組、字典和數(shù)據(jù)類(lèi)的替代品。在需要?jiǎng)?chuàng)建占用空間更少的不可變類(lèi)時(shí),命名元組就是很好的選擇。

    題目46:按照題目要求寫(xiě)出對(duì)應(yīng)的函數(shù)。

    要求:寫(xiě)一個(gè)函數(shù),傳入一個(gè)有若干個(gè)整數(shù)的列表,該列表中某個(gè)元素出現(xiàn)的次數(shù)超過(guò)了50%,返回這個(gè)元素。

    def more_than_half(items):temp, times = None, 0for item in items:if times == 0:temp = itemtimes += 1else:if item == temp:times += 1else:times -= 1return temp

    點(diǎn)評(píng):LeetCode上的題目,在Python面試中出現(xiàn)過(guò),利用元素出現(xiàn)次數(shù)超過(guò)了50%這一特征,出現(xiàn)和temp相同的元素就將計(jì)數(shù)值加1,出現(xiàn)和temp不同的元素就將計(jì)數(shù)值減1。如果計(jì)數(shù)值為0,說(shuō)明之前出現(xiàn)的元素已經(jīng)對(duì)最終的結(jié)果沒(méi)有影響,用temp記下當(dāng)前元素并將計(jì)數(shù)值置為1。最終,出現(xiàn)次數(shù)超過(guò)了50%的這個(gè)元素一定會(huì)被賦值給變量temp。

    題目47:按照題目要求寫(xiě)出對(duì)應(yīng)的函數(shù)。

    要求:寫(xiě)一個(gè)函數(shù),傳入的參數(shù)是一個(gè)列表(列表中的元素可能也是一個(gè)列表),返回該列表最大的嵌套深度。例如:列表[1, 2, 3]的嵌套深度為1,列表[[1], [2, [3]]]的嵌套深度為3。

    def list_depth(items):if isinstance(items, list):max_depth = 1for item in items:max_depth = max(list_depth(item) + 1, max_depth)return max_depthreturn 0

    點(diǎn)評(píng):看到題目應(yīng)該能夠比較自然的想到使用遞歸的方式檢查列表中的每個(gè)元素。

    題目48:按照題目要求寫(xiě)出對(duì)應(yīng)的裝飾器。

    要求:有一個(gè)通過(guò)網(wǎng)絡(luò)獲取數(shù)據(jù)的函數(shù)(可能會(huì)因?yàn)榫W(wǎng)絡(luò)原因出現(xiàn)異常),寫(xiě)一個(gè)裝飾器讓這個(gè)函數(shù)在出現(xiàn)指定異常時(shí)可以重試指定的次數(shù),并在每次重試之前隨機(jī)延遲一段時(shí)間,最長(zhǎng)延遲時(shí)間可以通過(guò)參數(shù)進(jìn)行控制。

    方法一:

    from functools import wraps from random import random from time import sleepdef retry(*, retry_times=3, max_wait_secs=5, errors=(Exception, )):def decorate(func):@wraps(func)def wrapper(*args, **kwargs):for _ in range(retry_times):try:return func(*args, **kwargs)except errors:sleep(random() * max_wait_secs)return Nonereturn wrapperreturn decorate

    方法二:

    from functools import wraps from random import random from time import sleepclass Retry(object):def __init__(self, *, retry_times=3, max_wait_secs=5, errors=(Exception, )):self.retry_times = retry_timesself.max_wait_secs = max_wait_secsself.errors = errorsdef __call__(self, func):@wraps(func)def wrapper(*args, **kwargs):for _ in range(self.retry_times):try:return func(*args, **kwargs)except self.errors:sleep(random() * self.max_wait_secs)return Nonereturn wrapper

    點(diǎn)評(píng):我們不止一次強(qiáng)調(diào)過(guò),裝飾器幾乎是Python面試必問(wèn)內(nèi)容,這個(gè)題目比之前的題目稍微復(fù)雜一些,它需要的是一個(gè)參數(shù)化的裝飾器。

    題目49:寫(xiě)一個(gè)函數(shù)實(shí)現(xiàn)字符串反轉(zhuǎn),盡可能寫(xiě)出你知道的所有方法。

    點(diǎn)評(píng):爛大街的題目,基本上算是送人頭的題目。

    方法一:反向切片

    def reverse_string(content):return content[::-1]

    方法二:反轉(zhuǎn)拼接

    def reverse_string(content):return ''.join(reversed(content))

    方法三:遞歸調(diào)用

    def reverse_string(content):if len(content) <= 1:return contentreturn reverse_string(content[1:]) + content[0]

    方法四:雙端隊(duì)列

    from collections import dequedef reverse_string(content):q = deque()q.extendleft(content)return ''.join(q)

    方法五:反向組裝

    from io import StringIOdef reverse_string(content):buffer = StringIO()for i in range(len(content) - 1, -1, -1):buffer.write(content[i])return buffer.getvalue()

    方法六:反轉(zhuǎn)拼接

    def reverse_string(content):return ''.join([content[i] for i in range(len(content) - 1, -1, -1)])

    方法七:半截交換

    def reverse_string(content):length, content= len(content), list(content)for i in range(length // 2):content[i], content[length - 1 - i] = content[length - 1 - i], content[i]return ''.join(content)

    方法八:對(duì)位交換

    def reverse_string(content):length, content= len(content), list(content)for i, j in zip(range(length // 2), range(length - 1, length // 2 - 1, -1)):content[i], content[j] = content[j], content[i]return ''.join(content)

    擴(kuò)展:這些方法其實(shí)都是大同小異的,面試的時(shí)候能夠給出幾種有代表性的就足夠了。給大家留一個(gè)思考題,上面這些方法,哪些做法的性能較好呢?我們之前提到過(guò)剖析代碼性能的方法,大家可以用這些方法來(lái)檢驗(yàn)下你給出的答案是否正確。

    題目50:按照題目要求寫(xiě)出對(duì)應(yīng)的函數(shù)。

    要求:列表中有1000000個(gè)元素,取值范圍是[1000, 10000),設(shè)計(jì)一個(gè)函數(shù)找出列表中的重復(fù)元素。

    def find_dup(items: list):dups = [0] * 9000for item in items:dups[item - 1000] += 1for idx, val in enumerate(dups):if val > 1:yield idx + 1000

    點(diǎn)評(píng):這道題的解法和計(jì)數(shù)排序的原理一致,雖然元素的數(shù)量非常多,但是取值范圍[1000, 10000)并不是很大,只有9000個(gè)可能的取值,所以可以用一個(gè)能夠保存9000個(gè)元素的dups列表來(lái)記錄每個(gè)元素出現(xiàn)的次數(shù),dups列表所有元素的初始值都是0,通過(guò)對(duì)items列表中元素的遍歷,當(dāng)出現(xiàn)某個(gè)元素時(shí),將dups列表對(duì)應(yīng)位置的值加1,最后dups列表中值大于1的元素對(duì)應(yīng)的就是items列表中重復(fù)出現(xiàn)過(guò)的元素。

    總結(jié)

    以上是生活随笔為你收集整理的一份Python面试宝典的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    丁香视频 | 国产亚洲精品bv在线观看 | 久久精品久久精品久久精品 | 亚洲欧美视频在线 | 日本精品二区 | 国产精品毛片一区二区 | 久久精品激情 | 天天射狠狠干 | 国产精品国内免费一区二区三区 | 日韩网站免费观看 | av免费观看在线 | 国产高清av免费在线观看 | 黄色的网站免费看 | 日韩精品黄 | 97视频免费在线 | 国产精品久久久久毛片大屁完整版 | 四虎在线免费观看 | 欧美在线观看视频一区二区 | av高清在线观看 | 超碰人人乐 | 国模吧一区 | 午夜精品视频福利 | av免费福利 | 亚洲综合视频在线观看 | www.com久久 | 在线成人高清电影 | 久久在草| 亚洲精品美女在线 | 成人aⅴ视频 | 草久视频在线观看 | 日韩欧美国产精品 | 毛片美女网站 | 午夜电影中文字幕 | 久草www | 国产日韩视频在线 | 777xxx欧美| 天天干天天操天天做 | 西西大胆啪啪 | 在线免费黄色片 | 毛片黄色一级 | 亚洲精品高清在线观看 | 亚洲精品久久久久58 | 97免费视频在线播放 | 日韩视频一区二区三区在线播放免费观看 | 亚洲日本精品视频 | 婷香五月 | 国内精品一区二区 | 天天舔天天搞 | 五月天中文字幕mv在线 | 免费看一及片 | 中文字幕免费成人 | 精品91在线 | 亚洲久草在线视频 | 成年人免费电影在线观看 | 香蕉精品视频在线观看 | 人人看97| 久久久www成人免费精品 | 国产精品中文 | 九九九九精品九九九九 | 视频1区2区 | 久热av在线 | www天天干 | av在线播放免费 | 最新超碰在线 | 91九色蝌蚪视频网站 | 国产免费嫩草影院 | 国产精品成人品 | 中文国产成人精品久久一 | 日本免费久久高清视频 | 中文乱幕日产无线码1区 | 狠狠狠狠狠狠狠干 | 九九免费在线观看视频 | 亚洲专区路线二 | 免费福利影院 | 国产成人一区二区在线观看 | 黄色小网站免费看 | 久草在线视频中文 | 久久免费国产视频 | 午夜影院三级 | 在线观看视频亚洲 | 激情综合五月 | 国产午夜三级一二三区 | 麻豆一区在线观看 | 久久精品韩国 | 在线成人短视频 | 97超碰在线资源 | 免费观看国产视频 | 久久久久国产免费免费 | 国产999精品久久久久久绿帽 | 亚洲精品乱码久久久久久蜜桃91 | av手机在线播放 | 九色琪琪久久综合网天天 | 久久国产免费视频 | 992tv在线| 欧美性成人 | 波多野结衣视频一区二区三区 | 夜夜操天天操 | 免费观看av网站 | 黄色在线观看免费网站 | 福利视频午夜 | 欧美伦理一区 | 亚洲尺码电影av久久 | 日韩电影中文 | 天天射日 | 91九色最新地址 | 亚洲精品黄网站 | 黄网站免费大全入口 | 久久男人中文字幕资源站 | 狠狠做深爱婷婷综合一区 | 特级黄色一级 | 夜夜骑日日操 | 激情综合久久 | 天天干天天干天天 | 人人草天天草 | 91伊人久久大香线蕉蜜芽人口 | 国产精品99久久免费观看 | 亚洲精品国久久99热 | 亚洲不卡123| 国产在线不卡一区 | 欧美成人久久 | www.狠狠干 | 国产首页 | 日日操夜 | 久久免费高清 | 91精品啪在线观看国产 | 欧美吞精| 黄色www | 亚洲日韩精品欧美一区二区 | 欧美成人精品三级在线观看播放 | 午夜私人影院 | 99久久99久久精品国产片果冰 | 国产精品网站一区二区三区 | 操综合 | 在线观看免费一区 | 久草在线电影网 | 国产老妇av | 国产精品成人国产乱 | 欧美日韩在线播放 | 日本三级人妇 | 欧美日韩中文视频 | 99久久精品久久久久久清纯 | 深爱婷婷 | 国产破处在线视频 | 国产综合久久 | 欧美作爱视频 | 97视频久久久 | av一区二区三区在线 | 日韩中文字幕第一页 | 99热这里只有精品免费 | 欧美激情一区不卡 | 国产午夜精品理论片在线 | 日韩最新理论电影 | 国产一级三级 | 男女拍拍免费视频 | 久久久久久国产精品999 | 欧美日韩在线观看不卡 | 久久免费国产视频 | 亚洲尺码电影av久久 | 超碰在线人人艹 | 91 在线视频播放 | 69国产精品成人在线播放 | 麻豆久久久久 | 在线激情影院一区 | 香蕉久久久久 | 五月天亚洲激情 | 香蕉久久久久久av成人 | 成人网在线免费视频 | 国产字幕在线播放 | 欧美成人91 | 成人久久免费视频 | 黄色免费高清视频 | 国内精品久久久久久久久 | 日韩最新理论电影 | 天天综合网入口 | 在线看污网站 | 国产剧情久久 | 亚洲一区av | 蜜臀av性久久久久蜜臀aⅴ流畅 | 亚洲蜜桃在线 | 成人黄色电影在线 | 在线免费观看黄网站 | 久久99欧美 | 亚洲日韩欧美视频 | 国产正在播放 | 久久久午夜精品理论片中文字幕 | 少妇bbw搡bbbb搡bbb | 国产精品美女www爽爽爽视频 | 天天操人| 日日干综合 | 四虎国产精品免费观看视频优播 | 狠狠地操| 人人爽人人澡人人添人人人人 | 国产999精品久久久久久麻豆 | 综合国产在线观看 | 日本性生活免费看 | 九九久久国产 | 特级毛片网站 | 亚洲欧洲成人 | 国产精品永久久久久久久www | 亚洲一区网站 | 亚洲精品福利视频 | 啪啪凸凸| 一级欧美日韩 | 香蕉成人在线视频 | 一级淫片在线观看 | 摸bbb搡bbb搡bbbb| 999久久a精品合区久久久 | 激情图片久久 | 久久久国产精品人人片99精片欧美一 | 国产一区视频导航 | 中文字幕在线播放视频 | 国产高清精品在线 | 久久综合久色欧美综合狠狠 | 亚洲欧美日本一区二区三区 | 午夜影院在线观看18 | 97av视频在线观看 | 玖玖爱在线观看 | 日日干天天插 | 在线日韩视频 | 超碰在线天天 | 亚洲精品国久久99热 | 久久久久久美女 | 中文字幕在线观看视频一区二区三区 | 亚洲精品综合欧美二区变态 | 久久视频精品在线观看 | 国产色女人 | 亚洲精品国产综合久久 | 免费视频 三区 | 日韩免费在线视频 | 色综合久久久久综合 | 激情一区二区三区欧美 | 麻豆一级视频 | 草久中文字幕 | 国产视频一区二区在线观看 | 国内精品久久久 | 四虎国产精品免费观看视频优播 | 日韩videos高潮hd | 国产亚洲综合性久久久影院 | 久久免费99精品久久久久久 | 久热精品国产 | 欧美精品v国产精品v日韩精品 | 在线视频日韩一区 | 中文字幕一区二 | 成年人在线看片 | 二区中文字幕 | 久久福利在线 | 色综合天天色综合 | 91秒拍国产福利一区 | 超碰公开在线观看 | a黄色| 国语黄色片 | 亚洲欧洲一区二区在线观看 | 久久99热这里只有精品 | 国产裸体永久免费视频网站 | 黄色免费在线视频 | 国产精品女主播一区二区三区 | 2020天天干夜夜爽 | 麻豆影视网 | 国产精品视频免费看 | 911精品美国片911久久久 | 久操视频在线观看 | aaa免费毛片 | 成人三级av | 日韩欧美精品在线观看视频 | 日日碰狠狠躁久久躁综合网 | 91在线中字 | 中文字幕国产视频 | 国产精品久久视频 | 色综合小说 | 久草免费福利在线观看 | 国产精品一区久久久久 | 国内精品久久久久影院男同志 | 久草在线视频网站 | 亚洲国产精品日韩 | 五月婷婷,六月丁香 | 91av资源网| 国产操在线 | 久热免费在线观看 | 久久精品国亚洲 | 国产精品久久久久久久久久久免费看 | 丝袜一区在线 | 精品久久一级片 | 天天综合视频在线观看 | 国产免费亚洲高清 | 四虎天堂 | 精品亚洲成人 | 国产欧美精品一区aⅴ影院 99视频国产精品免费观看 | 久久天天躁狠狠躁亚洲综合公司 | 91色综合 | 日本精品一区二区三区在线播放视频 | 在线观看第一页 | 中文国产字幕在线观看 | 国产精品美女久久久久久久久久久 | 欧美在线一二区 | 欧美日韩中 | 亚洲一区二区三区91 | 日韩欧美视频一区二区三区 | 亚洲国产日韩av | 国产系列在线观看 | 亚洲国产精品一区二区久久hs | 久久久久久久久久电影 | 91免费版成人 | av成人动漫 | 在线观看色网站 | 精品国产自在精品国产精野外直播 | 麻花豆传媒mv在线观看 | av千婊在线免费观看 | 亚洲免费a| 99久久精品国产一区 | 伊人干综合 | 日韩成人看片 | 国产 日韩 中文字幕 | 中文日韩在线 | 99久久这里有精品 | 久久久久成人免费 | 久草电影在线 | 在线观看国产一区 | 久久超碰网 | 亚洲精品大全 | 2019精品手机国产品在线 | 高清国产午夜精品久久久久久 | 久久久国产影视 | 片网站 | 精品国产久| 免费a现在观看 | 久久精品久久综合 | 欧美日韩免费网站 | 91视频com | av专区在线| 欧美aaa视频 | 波多野结衣在线播放一区 | 黄色三级免费 | 精品一区二区在线看 | 久久久久99999 | 欧美aa在线 | 国产成人精品一区二区三区福利 | 亚洲成人资源网 | 国产午夜在线 | 精品人人人人 | 日韩四虎 | 国产精品丝袜久久久久久久不卡 | 亚洲不卡av一区二区三区 | 色综合久久综合 | 91插插插网站 | 日韩高清www | 在线а√天堂中文官网 | 国产精品成人一区二区三区吃奶 | 91色一区二区三区 | 黄色一区二区在线观看 | 日本高清xxxx | 在线成人观看 | 国产一区二区在线影院 | 伊人官网 | 午夜 久久 tv | 天天干天天在线 | 黄色网在线播放 | 久久成人黄色 | 亚洲 欧洲av | 新版资源中文在线观看 | 婷婷九月丁香 | 丁香五月亚洲综合在线 | 国产精品一区二区三区视频免费 | 日韩大片在线免费观看 | 九九亚洲视频 | 久久精品美女 | 韩日精品中文字幕 | 亚洲精品国产第一综合99久久 | 久久国产成人午夜av影院潦草 | 又湿又紧又大又爽a视频国产 | 日韩精品免费专区 | 免费视频你懂得 | 丁香亚洲| 国产色婷婷精品综合在线手机播放 | 亚洲高清视频在线观看 | 亚洲丝袜中文 | 成人黄色小说网 | 色综合久久久久久久久五月 | 亚州性色 | 久久精品精品电影网 | 国产精品综合av一区二区国产馆 | 奇米影视777影音先锋 | 国产视频一区二区在线播放 | 蜜臀av夜夜澡人人爽人人桃色 | 国产在线成人 | 久久1区| 狠狠干成人综合网 | 久草在线视频首页 | 久久精品99视频 | 欧美亚洲久久 | 国产一区二区三区视频在线 | 国产成人在线观看 | 中文字幕观看在线 | 国产精品网在线观看 | 国产精品美女久久久久久网站 | 国产一区成人在线 | 欧美精品免费一区二区 | 亚洲精品乱码久久久久久写真 | 国产精品久久久久久影院 | 西西444www大胆无视频 | 久久精品国产免费看久久精品 | 最近最新中文字幕视频 | 五月天综合网站 | 99国产精品免费网站 | 亚洲黄色精品 | 天天色天天骑天天射 | 精品国产亚洲一区二区麻豆 | 在线观看精品一区 | 亚洲91视频 | 国产成人黄色av | 亚洲精品国 | av丝袜美腿 | 国产精品精品久久久久久 | 婷婷久久婷婷 | 国产视频资源在线观看 | 精品国产一区二区三区av性色 | 视频在线精品 | 中文字幕在线播放日韩 | 免费在线观看av网址 | 欧美视频日韩视频 | 日韩av一区二区在线播放 | 婷婷丁香激情五月 | 中文字幕在线人 | 在线视频手机国产 | 国产麻豆精品传媒av国产下载 | 亚洲久草在线 | 午夜精品久久久久久久99 | 久草综合视频 | 激情五月六月婷婷 | 在线视频你懂 | 二区视频在线 | 人人天天夜夜 | 日韩精品免费在线播放 | a级一a一级在线观看 | 日韩网站在线播放 | 亚洲国产日韩欧美在线 | 草久在线播放 | 日韩网页 | 最新精品视频在线 | 国产成人av综合色 | 97视频人人澡人人爽 | 日韩激情网 | 色婷婷综合久久久中文字幕 | 成人av资源在线 | 97在线观看 | 国产在线精品视频 | 999久久国精品免费观看网站 | 国产精品久久久久久久久久久免费 | 九九热精品视频在线播放 | 91在线国内视频 | 久久艹艹 | 国产成人精品久久久久蜜臀 | 久久久久久电影 | 69国产精品视频 | 国产精品第一视频 | 在线观看av小说 | 亚洲九九影院 | 天天草夜夜 | 91成人区| 九色琪琪久久综合网天天 | 久久视频在线观看免费 | 国产一区二区不卡视频 | 亚洲欧美国产精品18p | 国产小视频在线 | 青草草在线 | 欧美日韩亚洲在线观看 | 亚洲精品高清在线观看 | 精品主播网红福利资源观看 | 国产一二三区av | 91免费视频黄 | 国产精品福利无圣光在线一区 | 日日躁天天躁 | 成人午夜电影网站 | 一区中文字幕电影 | 亚洲精品综合一二三区在线观看 | 国产高清精品在线观看 | 国产免费二区 | 国产精品一区二区三区免费视频 | 91精品一区二区在线观看 | 婷婷中文字幕在线观看 | 狠狠做深爱婷婷综合一区 | 国产一级一片免费播放放 | 五月婷在线观看 | 国产精品久久二区 | 人人超碰在线 | 狠狠色网| 国产精品久久久久久电影 | 欧美一级欧美一级 | 日韩区欧美久久久无人区 | 欧美日韩高清不卡 | 免费亚洲精品视频 | www最近高清中文国语在线观看 | 97夜夜澡人人爽人人免费 | 人人爽人人爽人人片 | 免费视频三区 | 久久亚洲美女 | 国产精品短视频 | 成人免费在线播放 | 丁香六月在线 | 涩涩网站在线观看 | 成年人免费在线看 | 在线黄色观看 | 中文乱幕日产无线码1区 | 精品久久久成人 | 91在线免费视频观看 | 欧美激情视频三区 | 久久欧洲视频 | 中文字幕中文字幕 | 色av网站| 国产精品午夜久久久久久99热 | 特及黄色片 | 在线免费观看涩涩 | 精品色999| 九九久久免费 | 九九热免费在线观看 | 国产精品国产三级国产aⅴ9色 | 国产精品一区二区在线免费观看 | 波多野结衣在线播放一区 | 久久久久99精品成人片三人毛片 | 日韩av片无码一区二区不卡电影 | 一二三精品视频 | 在线观看中文字幕第一页 | 日韩精品一区二区三区外面 | 国产国语在线 | av高清在线观看 | 99re8这里有精品热视频免费 | 成年人免费看 | 丝袜美腿av | 欧美日韩国产欧美 | 在线看成人 | 日韩在线不卡av | 2024国产在线| 一级成人免费 | 婷婷色综 | 国产精品一区二区久久久久 | 亚洲丁香日韩 | 在线探花 | 91禁看片 | 91av色| 色婷婷视频 | 伊人永久 | 亚洲在线高清 | 日韩精品一区二区三区高清免费 | 日韩精品久久久久久久电影99爱 | 免费在线色电影 | 欧美精品久久久久久久免费 | 中文字幕二区 | 视频精品一区二区三区 | 久草视频免费 | 久久人人爽视频 | 97超碰在线久草超碰在线观看 | 粉嫩av一区二区三区四区在线观看 | 亚洲美女在线一区 | 日产乱码一二三区别在线 | 97碰在线| 狠狠操综合 | 日韩高清三区 | 人人爱人人爽 | 在线观看视频一区二区三区 | 欧美日韩高清一区二区 国产亚洲免费看 | 成人一区二区三区在线 | 中文av免费 | 久久精品在线视频 | 亚洲国产中文字幕在线视频综合 | 久久草在线免费 | 欧美国产日韩一区二区三区 | 久久九九影视 | 久久夜色网 | 日日夜夜综合 | 中文字幕免费高清在线观看 | 国产精品av免费观看 | 欧美日本啪啪无遮挡网站 | 激情综合五月 | 黄色免费大片 | 亚洲视频资源在线 | 欧美国产视频在线 | 国产福利免费在线观看 | 日韩在线无 | 成 人 黄 色 免费播放 | 久久国产精品久久w女人spa | 日韩丝袜在线观看 | 国产资源网 | 91中文字幕在线视频 | 六月丁香在线观看 | 欧美日韩国产亚洲乱码字幕 | 国产99一区 | 久久久久国产a免费观看rela | 国产免费a | 天天爽人人爽夜夜爽 | 日韩理论电影网 | 97看片网 | 成人小视频免费在线观看 | 国产成人在线观看免费 | 国产在线观看99 | 91在线porny国产在线看 | 亚洲视频在线观看 | 久保带人| 99精品网站| 美女黄频视频大全 | av免费网站 | 国产一级免费在线 | 国产一区二区三区高清播放 | 91精品国产一区二区三区 | 国产在线播放观看 | 国产在线色| 永久免费视频国产 | 首页中文字幕 | 麻豆高清免费国产一区 | 99精品乱码国产在线观看 | 日韩精品不卡在线观看 | 亚洲国产精品久久久久 | 久久成人亚洲欧美电影 | 免费观看午夜视频 | 日韩剧 | 狠狠狠狠狠狠干 | 69国产盗摄一区二区三区五区 | 亚洲理论在线 | 97超碰成人在线 | 黄色影院在线观看 | 久久久久亚洲国产精品 | 久久精品一二三区白丝高潮 | 99亚洲精品| 国产首页 | 999久久久久久久久久久 | 日韩理论片中文字幕 | 久久久亚洲影院 | 亚洲另类视频 | 亚洲精品国产精品久久99 | 中文字幕在线观看一区二区 | 久久久蜜桃一区二区 | 成人app在线播放 | 日韩一级成人av | 黄色在线免费观看网址 | 欧美午夜久久久 | 久久国产美女视频 | 国产手机在线观看 | 国产视频精品在线 | 欧美电影在线观看 | av在线播放亚洲 | 在线视频 影院 | 一区二区三区免费播放 | 香蕉视频在线免费 | 亚洲精品乱码白浆高清久久久久久 | 国产午夜一级毛片 | 一级α片免费看 | 久久国产精品久久久久 | 五月天综合激情网 | 国产91全国探花系列在线播放 | 久久久国产一区二区三区 | 精品久久久久久久久久久院品网 | 2020天天干天天操 | 毛片一二区 | 五月天久久婷 | 五月天堂网 | 中文字幕久久精品一区 | 99精品视频免费全部在线 | 男女日麻批| 揉bbb玩bbb少妇bbb | 国产成人综合图片 | av免费在线观看网站 | 日韩免费中文 | 最近日本字幕mv免费观看在线 | 国产中文欧美日韩在线 | 视频 天天草 | 五月婷婷深开心 | 天天干夜夜爽 | 亚洲黄色高清 | 日韩电影中文字幕 | 亚洲涩综合 | 婷婷五天天在线视频 | 天天草天天插 | 国产精品女人久久久 | 天堂在线视频中文网 | 毛片精品免费在线观看 | 天天射射天天 | 天天爽天天爽 | 国产精品久久av | 精品一区二区在线免费观看 | 国产精品久久久久久久久久三级 | 天天在线免费视频 | 欧美激情精品久久久久 | 久久国产精品成人免费浪潮 | 国产精品女视频 | 国产香蕉97碰碰碰视频在线观看 | 99久久夜色精品国产亚洲96 | 国产精品久久嫩一区二区免费 | 99一区二区三区 | 亚洲精品在线视频播放 | 人人爽久久涩噜噜噜网站 | 国内久久久久 | 国产夫妻性生活自拍 | 黄色片视频在线观看 | 久久久久成人精品亚洲国产 | 一区二区三区免费看 | 久久久国产精品人人片99精片欧美一 | 亚洲综合欧美激情 | 亚洲精品国产自产拍在线观看 | 精品久久一级片 | 开心激情五月婷婷 | 久久资源总站 | 欧美日韩成人一区 | 日本免费一二三区 | 国产精品免费不卡 | 欧美色综合天天久久综合精品 | 天天曰天天爽 | 欧美日韩另类在线 | 一区二区三区日韩视频在线观看 | 激情欧美xxxx | 日日操天天操夜夜操 | 亚洲狠狠婷婷综合久久久 | 久久久久久久久网站 | 激情av网 | 伊人五月在线 | 国产精品午夜久久久久久99热 | 欧美精品一区二区在线播放 | 成人av播放 | 免费日韩 精品中文字幕视频在线 | 久久噜噜少妇网站 | 99久久日韩精品免费热麻豆美女 | 91资源在线 | 精品久久网 | 国产精品理论片在线观看 | 久久人人爽人人片 | 免费在线中文字幕 | 国产精品夜夜夜一区二区三区尤 | 欧美欧美 | 99精品毛片 | 99riav1国产精品视频 | 亚洲国产97在线精品一区 | 亚洲涩涩涩涩涩涩 | 久久综合九色欧美综合狠狠 | 天天操天天插 | 午夜三级福利 | 国产精品久久一区二区无卡 | 亚洲狠狠婷婷 | 丝袜美腿亚洲综合 | 久久久国产精品一区二区中文 | 国产一区二区不卡视频 | 伊人五月天 | 国产黄色精品在线 | 久久精品99国产 | 免费观看午夜视频 | 91精品国产高清自在线观看 | av黄在线播放 | 久久综合影院 | 亚洲精品91天天久久人人 | 丁香激情五月 | 色综合久久五月 | 亚洲精品久久久蜜桃直播 | 在线观影网站 | 91丨九色丨国产在线 | a在线观看视频 | 国产精品电影一区二区 | 亚洲国产精品第一区二区 | 免费av看片 | 精品嫩模福利一区二区蜜臀 | 亚洲电影久久久 | 视频国产一区二区三区 | 欧美色婷婷 | 日韩中文字幕在线看 | 国产视频在线免费 | www.精选视频.com | 97热在线观看 | 九九九在线观看 | 91免费看黄色 | 欧美日韩免费观看一区二区三区 | 精品99久久 | 网站免费黄色 | 福利片免费看 | 久久不卡国产精品一区二区 | 色先锋av资源中文字幕 | 久久久综合香蕉尹人综合网 | av一级久久 | 日日碰夜夜爽 | 欧美一区二区三区不卡 | 国产又粗又长的视频 | 久久婷婷视频 | 激情综合色图 | 天天舔天天搞 | 天天拍天天草 | 国产精品1区2区 | 日本精品一二区 | 中文字幕人成一区 | 在线性视频日韩欧美 | 国产伦理久久精品久久久久_ | 在线免费黄色 | 免费a级黄色毛片 | 91tv国产成人福利 | 免费观看91| 99视频久久 | 久久96国产精品久久99软件 | 欧美日韩免费在线观看视频 | 奇米网在线观看 | 黄色网在线播放 | 日韩中文字幕免费电影 | 久久这里只有精品久久 | 精品视频在线免费观看 | 日本三级久久 | 五月色婷 | 九九久久视频 | 久草在线99| 91九色porny蝌蚪视频 | 97香蕉久久国产在线观看 | 免费欧美高清视频 | 天天av在线播放 | 久久免费高清视频 | 成人av观看| 久久免费观看视频 | 亚州精品一二三区 | 91免费在线播放 | 亚洲年轻女教师毛茸茸 | 91av网址| 丁香视频 | 国产激情电影综合在线看 | 午夜精品久久久久久久久久久久 | 亚洲成aⅴ人片久久青草影院 | 亚洲精品乱码久久久久久蜜桃动漫 | 日韩av中文字幕在线 | 国产成人黄色av | 国产精品 欧美 日韩 | 国产区精品在线观看 | 色www. | 色干干| 麻豆视频在线免费 | 国产一级特黄电影 | 91久久偷偷做嫩草影院 | 最近最新中文字幕 | 精品国产aⅴ一区二区三区 在线直播av | 国产一线二线三线在线观看 | 中日韩欧美精彩视频 | 亚洲热视频 | 国产成人免费在线观看 | 国产在线超碰 | 久久手机在线视频 | 国产v欧美 | 国偷自产中文字幕亚洲手机在线 | www.久久免费视频 | 三级av小说 | 国产一二区在线观看 | 国产成人在线综合 | 日韩精品欧美一区 | 麻豆一区在线观看 | 国产成人久久av977小说 | 欧美日韩成人一区 | 国产va精品免费观看 | 国产一区二区久久久久 | 综合色婷婷| 日韩二区在线 | 国产999视频 | 日韩国产高清在线 | 丁香在线视频 | 久草久草久草久草 | 激情一区二区三区欧美 | 在线看毛片网站 | 色黄www小说 | 免费观看黄色av | 国产五月色婷婷六月丁香视频 | 午夜黄色影院 | 亚洲国产精品一区二区久久,亚洲午夜 | 激情网在线观看 | 97色婷婷人人爽人人 | 91av在线看 | 久久电影中文字幕视频 | 91夫妻视频 | 一级国产视频 | 91高清完整版在线观看 | 超碰av在线播放 | 在线观看中文字幕亚洲 | 有码中文字幕在线观看 | 久久你懂的 | 国产精品99久久久久久小说 | www.97视频| 精品成人久久 | 久久综合色一综合色88 | 国产亚洲婷婷免费 | 亚洲激精日韩激精欧美精品 | 国产一线二线三线性视频 | 成人动漫一区二区三区 | jizz18欧美18| 日日干日日 | 天天天综合 | 亚洲三级毛片 | 免费在线观看av网址 | 日本视频久久久 | 黄色av一级 | 日韩三级视频在线看 | av片无限看 | 黄在线免费看 | 国产一二三四在线观看视频 | 成人a在线观看高清电影 | 精品一区二区在线免费观看 | 国产不卡视频 | av在线进入 | 一区二区三区电影大全 | 久久精品一 | 国产 在线 高清 精品 | 欧美日韩国产精品一区二区 | 日韩在线观看第一页 | 日本黄色黄网站 | 91精品办公室少妇高潮对白 | 一级黄色片在线播放 | 天天躁日日躁狠狠 | 亚洲免费av在线播放 | 国产乱对白刺激视频在线观看女王 | 欧美黑人巨大xxxxx | 91在线免费视频 | 国产短视频在线播放 | 免费观看一级成人毛片 | 韩日精品在线 | 91成人免费在线视频 | 久久av不卡 | 在线国产精品视频 | 摸bbb搡bbb搡bbbb | 午夜色大片在线观看 | 亚洲视频在线视频 | 99热精品在线 | 天天干,夜夜操 | 中文字幕一区二区三区四区久久 | 天天艹天天操 | 国产在线精品二区 | 欧美精品第一 | 玖草在线观看 | 91免费试看 | 久久成人国产精品一区二区 | 婷婷深爱| 91热视频| 在线看片一区 | 在线精品亚洲 | 欧美综合干 | 午夜av免费在线观看 | 免费黄色一区 | 521色香蕉网站在线观看 | 91欧美视频网站 | 日日躁夜夜躁aaaaxxxx | 亚洲精品www久久久 www国产精品com | 国产手机在线观看视频 | aaa毛片视频| 婷婷伊人综合亚洲综合网 | 黄色网在线播放 | 69国产成人综合久久精品欧美 | 日韩va亚洲va欧美va久久 | 日韩经典一区二区三区 | 国产精品久久影院 | 国产亚洲婷婷免费 | 二区三区在线观看 | 最近高清中文字幕 | 久久电影中文字幕视频 | 亚洲深夜影院 | 蜜臀久久99静品久久久久久 | 中文字幕在线一区二区三区 | 久久久精品国产免费观看同学 | 天天操天天操一操 | 日韩精品久久一区二区 | 992tv人人网tv亚洲精品 | 日韩视频精品在线 | 国产精品毛片完整版 | 黄色三级网站在线观看 | 狠狠色狠狠色综合日日92 | 丁香五月网久久综合 | 免费视频三区 | 久久艹艹 | 人人爽人人看 | 激情欧美xxxx | 天天射综合 | 99视频国产精品免费观看 | 黄色亚洲片 | 一区二区欧美在线观看 | 丁香激情综合国产 | 黄色成人av | 成人午夜网 | 亚洲一区二区三区毛片 | 国产护士在线 | 中文字幕在线高清 | 国产视频精选在线 | 午夜视频在线网站 | 国产一区二区在线免费播放 | 免费进去里的视频 | 免费成人av在线看 | 精品一区二区久久久久久久网站 | 日韩在线观看a | 欧美国产日韩一区二区 | 久草视频看看 | 亚洲一区日韩精品 | 国产精品久久久久久婷婷天堂 | 久久精品精品电影网 | 亚洲精品国产精品国自产在线 | sm免费xx网站 | 国产成人精品亚洲日本在线观看 | 中文字幕免费一区 | 91福利区一区二区三区 | 日韩高清国产精品 | 久久国产精品久久久久 | 亚洲无吗天堂 | 在线观看亚洲精品 | 一区二区在线电影 | 自拍超碰在线 | 久久久久女教师免费一区 | 日韩欧美精选 | 在线三级中文 |