91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Python面試寶典之基礎篇-02

發布時間:2020-08-09 06:41:50 來源:ITPUB博客 閱讀:196 作者:千鋒Python唐小強 欄目:編程語言

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

Python面試寶典之基礎篇-02

題目006:說說Python中的淺拷貝和深拷貝。

點評:這個題目本身出現的頻率非常高,但是就題論題而言沒有什么技術含量。對于這種面試題,在 回答的時候一定要讓你的答案能夠超出面試官的預期,這樣才能 獲得更好的印象分。所以回答這個題目的要點不僅僅是能夠說出淺拷貝和深拷貝的區別,深拷貝的時候可能遇到的兩大問題,還要說出Python標準庫對淺拷貝和深拷貝的支持,然后可以說說列表、字典如何實現拷貝操作以及如何通過序列化和反序列的方式實現深拷貝,最后還可以提到設計模式中的原型模式以及它在項目中的應用。

淺拷貝通常只復制對象本身,而深拷貝不僅會復制對象,還會遞歸的復制對象所關聯的對象。深拷貝可能會遇到兩個問題:一是一個對象如果直接或間接的引用了自身,會導致無休止的遞歸拷貝;二是深拷貝可能對原本設計為多個對象共享的數據也進行拷貝。Python通過copy模塊中的copy和deepcopy函數來實現淺拷貝和深拷貝操作,其中deepcopy可以通過memo字典來保存已經拷貝過的對象,從而避免剛才所說的自引用遞歸問題;此外,可以通過copyreg模塊的pickle函數來定制指定類型對象的拷貝行為。

deepcopy函數的本質其實就是對象的一次序列化和一次返回序列化,面試題中還考過用自定義函數實現對象的深拷貝操作,顯然我們可以使用pickle模塊的dumps和loads來做到,代碼如下所示。


import pickle


my_deep_copy = lambda obj: pickle.loads(pickle.dumps(obj))

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


import copy
class PrototypeMeta(type):

    """實現原型模式的元類"""

    def __init__ (cls, *args, **kwargs):
       super().__init__(*args, **kwargs)
        # 為對象綁定clone方法來實現對象拷貝
       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是如何實現內存管理的?

點評:當面試官問到這個問題的時候,一個展示自己的機會就擺在面前了。你要先反問面試官:“你說的是官方的CPython解釋器嗎?”。這個反問可以展示出你了解過Python解釋器的不同的實現版本,而且你也知道面試官想問的是CPython。當然,很多面試官對不同的Python解釋器底層實現到底有什么差別也沒有概念。所以, 千萬不要覺得面試官一定比你強,懷揣著這份自信可以讓你更好的完成面試。

Python提供了自動化的內存管理,也就是說內存空間的分配與釋放都是由Python解釋器在運行時自動進行的,自動管理內存功能極大的減輕程序員的工作負擔,也能夠幫助程序員在一定程度上解決內存泄露的問題。以CPython解釋器為例,它的內存管理有三個關鍵點:引用計數、標記清理、分代收集。

引用計數:對于CPython解釋器來說,Python中的每一個對象其實就是PyObject結構體,它的內部有一個名為ob_refcnt 的引用計數器成員變量。程序在運行的過程中ob_refcnt的值會被更新并藉此來反映引用有多少個變量引用到該對象。當對象的引用計數值為0時,它的內存就會被釋放掉。


typedef 

struct _
object {

   _PyObject_HEAD_EXTRA
   Py_ssize_t ob_refcnt;
    struct _ typeobject * ob_type;
} PyObject;

以下情況會導致引用計數加1:

  • 對象被創建
  • 對象被引用
  • 對象作為參數傳入到一個函數中
  • 對象作為元素存儲到一個容器中

以下情況會導致引用計數減1:

  • 用del語句顯示刪除對象引用
  • 對象引用被重新賦值其他對象
  • 一個對象離開它所在的作用域
  • 持有該對象的容器自身被銷毀
  • 持有該對象的容器刪除該對象

可以通過sys模塊的getrefcount函數來獲得對象的引用計數。引用計數的內存管理方式在遇到循環引用的時候就會出現致命傷,因此需要其他的垃圾回收算法對其進行補充。

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

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

題目008:說一下你對Python中迭代器和生成器的理解。

點評:很多人面試者都會寫迭代器和生成器,但是卻無法準確的解釋什么是迭代器和生成器。如果你也有同樣的困惑,可以參考下面的回答。

迭代器是實現了迭代器協議的對象。跟其他編程語言不通,Python中沒有用于定義協議或表示約定的關鍵字,像interface、protocol這些單詞并不在Python語言的關鍵字列表中。Python語言通過魔法方法來表示約定,也就是我們所說的協議,而__next__和__iter__這兩個魔法方法就代表了迭代器協議。生成器是迭代器的語法升級版本,可以用更為簡單的代碼來實現一個迭代器。

面試中經常會讓面試者寫生成斐波那契數列的迭代器,下面給出參考代碼,其他的迭代器可以如法炮制。


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

如果用生成器的語法來改寫上面的代碼,代碼會簡單優雅很多。



def 
fib
(num):

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

可以通過for-in循環從迭代器對象中取出值,也可以使用next函數取出迭代器對象中的下一個值。

題目009:正則表達式的match方法和search方法有什么區別?

點評:正則表達式是字符串處理的重要工具,所以也是面試中經常考察的知識點。在Python中,使用正則表達式有兩種方式,一種是直接調用re模塊中的函數,傳入正則表達式和需要處理的字符串;一種是先通過re模塊的compile函數創建正則表達式對象,然后再通過對象調用方法并傳入需要處理的字符串。如果一個正則表達式被頻繁的使用,我們推薦后面這種方式,它會減少頻繁編譯同一個正則表達式所造成的開銷。

match方法是從字符串的起始位置進行正則表達式匹配,返回Match對象或None。search方法會掃描整個字符串來找尋匹配的模式,同樣也是返回Match對象或None。

題目010:下面這段代碼的執行結果是什么。



def 
multiply
():

    return [ lambda x: i * x for i in range( 4)]

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

運行結果:

[300, 300, 300, 300]

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

如果想得到[0, 100, 200, 300]這個結果,可以按照下面幾種方式來修改multiply函數。

方法一:使用生成器,讓函數獲得i的當前值。



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

方法二:使用偏函數,徹底避開閉包現象。


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面試寶典會持續更新,從基礎到項目實戰的內容都會慢慢覆蓋到。雖然每天只更新5個題目,但是每道題擴散出的信息量還是比較大的,希望對找工作的小伙伴所有幫助。

感謝大家一直以來的支持! 有正在學習Python的伙伴,或者準備轉行學習Python的,或者你是想打牢自己Python基礎的朋友,給你們整理的視頻教程也上架了!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

宁国市| 翁源县| 八宿县| 闻喜县| 昌黎县| 玛曲县| 宜宾市| 张家口市| 河池市| 博野县| 临沭县| 昆明市| 宽城| 五峰| 布尔津县| 锡林郭勒盟| 湾仔区| 赫章县| 英吉沙县| 育儿| 深水埗区| 关岭| 南雄市| 建宁县| 达日县| 三亚市| 贵德县| 平舆县| 富平县| 襄城县| 临西县| 田林县| 洛浦县| 安陆市| 略阳县| 东丽区| 建瓯市| 社旗县| 清远市| 修文县| 广汉市|