真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Python面試寶典之基礎(chǔ)篇-02

我覺(jué)得你如果正在找工作,我的Python面試寶典幾期教程,你一定得花時(shí)間看完了!

成都創(chuàng)新互聯(lián)公司服務(wù)項(xiàng)目包括旌陽(yáng)網(wǎng)站建設(shè)、旌陽(yáng)網(wǎng)站制作、旌陽(yáng)網(wǎng)頁(yè)制作以及旌陽(yáng)網(wǎng)絡(luò)營(yíng)銷(xiāo)策劃等。多年來(lái),我們專(zhuān)注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,旌陽(yáng)網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到旌陽(yáng)省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!

Python面試寶典之基礎(chǔ)篇-02

題目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 pickle

my_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í)更加高效,這也就是設(shè)計(jì)模式中的原型模式。我們可以通過(guò)元類(lèi)的方式來(lái)實(shí)現(xiàn)原型模式,代碼如下所示。


import copy
class 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):
   pass p1 = 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_EXTRA
   Py_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é)議。生成器是迭代器的語(yǔ)法升級(jí)版本,可以用更為簡(jiǎn)單的代碼來(lái)實(shí)現(xiàn)一個(gè)迭代器。

面試中經(jīng)常會(huì)讓面試者寫(xiě)生成斐波那契數(shù)列的迭代器,下面給出參考代碼,其他的迭代器可以如法炮制。


class Fib(object):

   def __init__( self, num):
        self.num = num
        self.a, self.b = 0, 1
        self.idx = 0

   def __iter__( self):
        return self

   def __next__( self):
        if self.idx < self.num:
            self.a, self.b = self.b, self.a + self.b
            self.idx += 1
            return self.a
       raise StopIteration()

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



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

可以通過(guò)for-in循環(huán)從迭代器對(duì)象中取出值,也可以使用next函數(shù)取出迭代器對(duì)象中的下一個(gè)值。

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

點(diǎn)評(píng):正則表達(dá)式是字符串處理的重要工具,所以也是面試中經(jīng)??疾斓闹R(shí)點(diǎn)。在Python中,使用正則表達(dá)式有兩種方式,一種是直接調(diào)用re模塊中的函數(shù),傳入正則表達(dá)式和需要處理的字符串;一種是先通過(guò)re模塊的compile函數(shù)創(chuàng)建正則表達(dá)式對(duì)象,然后再通過(guò)對(duì)象調(diào)用方法并傳入需要處理的字符串。如果一個(gè)正則表達(dá)式被頻繁的使用,我們推薦后面這種方式,它會(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 * i

print([m( 100) for m in multiply()])

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


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()])

溫馨提示:Python面試寶典會(huì)持續(xù)更新,從基礎(chǔ)到項(xiàng)目實(shí)戰(zhàn)的內(nèi)容都會(huì)慢慢覆蓋到。雖然每天只更新5個(gè)題目,但是每道題擴(kuò)散出的信息量還是比較大的,希望對(duì)找工作的小伙伴所有幫助。

感謝大家一直以來(lái)的支持! 有正在學(xué)習(xí)Python的伙伴,或者準(zhǔn)備轉(zhuǎn)行學(xué)習(xí)Python的,或者你是想打牢自己Python基礎(chǔ)的朋友,給你們整理的視頻教程也上架了!


分享標(biāo)題:Python面試寶典之基礎(chǔ)篇-02
當(dāng)前網(wǎng)址:http://weahome.cn/article/geppdi.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部