<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          很全的 Python 面試題

          共 11360字,需瀏覽 23分鐘

           ·

          2021-06-02 17:45

          來源:taizilongxu    鏈接:

          https://github.com/taizilongxu/interview_python


          Python語言特性


          1 Python的函數(shù)參數(shù)傳遞


          看兩個例子:

          a = 1
          def fun(a):
             a = 2
          fun(a)
          print a  # 1
          a = []
          def fun(a):
             a.append(1)
          fun(a)
          print a  # [1]

          所有的變量都可以理解是內(nèi)存中一個對象的“引用”,或者,也可以看似c中void*的感覺。


          這里記住的是類型是屬于對象的,而不是變量。而對象有兩種,“可更改”(mutable)與“不可更改”(immutable)對象。在python中,strings, tuples, 和numbers是不可更改的對象,而list,dict等則是可以修改的對象。(這就是這個問題的重點)


          當一個引用傳遞給函數(shù)的時候,函數(shù)自動復制一份引用,這個函數(shù)里的引用和外邊的引用沒有半毛關(guān)系了.所以第一個例子里函數(shù)把引用指向了一個不可變對象,當函數(shù)返回的時候,外面的引用沒半毛感覺.而第二個例子就不一樣了,函數(shù)內(nèi)的引用指向的是可變對象,對它的操作就和定位了指針地址一樣,在內(nèi)存里進行修改.


          如果還不明白的話,這里有更好的解釋: http://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference


          2 Python中的元類(metaclass)


          這個非常的不常用,但是像ORM這種復雜的結(jié)構(gòu)還是會需要的,詳情請看:《兩句話掌握Python最難知識點——元類


          3 @staticmethod和@classmethod


          Python其實有3個方法,即靜態(tài)方法(staticmethod),類方法(classmethod)和實例方法,如下:

          def foo(x):
             print "executing foo(%s)"%(x)

          class A(object):
             def foo(self,x):
                 print "executing foo(%s,%s)"%(self,x)

             @classmethod
             def class_foo(cls,x):
                 print "executing class_foo(%s,%s)"%(cls,x)

             @staticmethod
             def static_foo(x):
                 print "executing static_foo(%s)"%x

          a=A()

          這里先理解下函數(shù)參數(shù)里面的self和cls.這個self和cls是對類或者實例的綁定,對于一般的函數(shù)來說我們可以這么調(diào)用foo(x),這個函數(shù)就是最常用的,它的工作跟任何東西(類,實例)無關(guān).對于實例方法,我們知道在類里每次定義方法的時候都需要綁定這個實例,就是foo(self, x),為什么要這么做呢?因為實例方法的調(diào)用離不開實例,我們需要把實例自己傳給函數(shù),調(diào)用的時候是這樣的a.foo(x)(其實是foo(a, x)).類方法一樣,只不過它傳遞的是類而不是實例,A.class_foo(x).注意這里的self和cls可以替換別的參數(shù),但是python的約定是這倆,還是不要改的好.


          對于靜態(tài)方法其實和普通的方法一樣,不需要對誰進行綁定,唯一的區(qū)別是調(diào)用的時候需要使用a.static_foo(x)或者A.static_foo(x)來調(diào)用.




          更多關(guān)于這個問題:http://stackoverflow.com/questions/136097/what-is-the-difference-between-staticmethod-and-classmethod-in-python


          4 類變量和實例變量

          class Person:
             name="aaa"

          p1=Person()
          p2=Person()
          p1.name="bbb"
          print p1.name  # bbb
          print p2.name  # aaa
          print Person.name  # aaa

          類變量就是供類使用的變量,實例變量就是供實例使用的.


          這里p1.name="bbb"是實例調(diào)用了類變量,這其實和上面第一個問題一樣,就是函數(shù)傳參的問題,p1.name一開始是指向的類變量name="aaa",但是在實例的作用域里把類變量的引用改變了,就變成了一個實例變量,self.name不再引用Person的類變量name了.


          可以看看下面的例子:

          class Person:
             name=[]

          p1=Person()
          p2=Person()
          p1.name.append(1)
          print p1.name  # [1]
          print p2.name  # [1]
          print Person.name  # [1]

          參考:http://stackoverflow.com/questions/6470428/catch-multiple-exceptions-in-one-line-except-block


          5 Python自省


          這個也是python彪悍的特性.


          自省就是面向?qū)ο蟮恼Z言所寫的程序在運行時,所能知道對象的類型.簡單一句就是運行時能夠獲得對象的類型.比如type(),dir(),getattr(),hasattr(),isinstance().


          6 字典推導式


          可能你見過列表推導時,卻沒有見過字典推導式,在2.7中才加入的:

          d = {key: value for (key, value) in iterable}

          7 Python中單下劃線和雙下劃線

          >>> class MyClass():
          ...    def __init__(self):
          ...            self.__superprivate = "Hello"
          ...            self._semiprivate = ", world!"
          ...
          >>> mc = MyClass()
          >>> print mc.__superprivate
          Traceback (most recent call last):
           File "<stdin>", line 1, in <module>
          AttributeError: myClass instance has no attribute '__superprivate'
          >>> print mc._semiprivate
          , world!
          >>> print mc.__dict__
          {'_MyClass__superprivate': 'Hello', '_semiprivate': ', world!'}

          __foo__:一種約定,Python內(nèi)部的名字,用來區(qū)別其他用戶自定義的命名,以防沖突.


          _foo:一種約定,用來指定變量私有.程序員用來指定私有變量的一種方式.


          __foo:這個有真正的意義:解析器用_classname__foo來代替這個名字,以區(qū)別和其他類相同的命名.


          詳情見:http://stackoverflow.com/questions/1301346/the-meaning-of-a-single-and-a-double-underscore-before-an-object-name-in-python


          或者: http://www.zhihu.com/question/19754941


          8 字符串格式化:%和.format


          .format在許多方面看起來更便利.對于%最煩人的是它無法同時傳遞一個變量和元組.你可能會想下面的代碼不會有什么問題:

          "hi there %s" % name

          但是,如果name恰好是(1,2,3),它將會拋出一個TypeError異常.為了保證它總是正確的,你必須這樣做:

          "hi there %s" % (name,)   # 提供一個單元素的數(shù)組而不是一個參數(shù)

          但是有點丑..format就沒有這些問題.你給的第二個問題也是這樣,.format好看多了.


          你為什么不用它?


          • 不知道它(在讀這個之前)

          • 為了和Python2.5兼容(譬如logging庫建議使用%(issue #4))


          http://stackoverflow.com/questions/5082452/python-string-formatting-vs-format


          9 迭代器和生成器


          這個是stackoverflow里python排名第一的問題,值得一看: http://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do-in-python


          這是中文版: http://taizilongxu.gitbooks.io/stackoverflow-about-python/content/1/README.html


          10 *args and **kwargs


          用*args和**kwargs只是為了方便并沒有強制使用它們.


          當你不確定你的函數(shù)里將要傳遞多少參數(shù)時你可以用*args.例如,它可以傳遞任意數(shù)量的參數(shù):

          >>> def print_everything(*args):
                 for count, thing in enumerate(args):
          ...        print '{0}. {1}'.format(count, thing)
          ...
          >>> print_everything('apple', 'banana', 'cabbage')
          0. apple
          1. banana
          2. cabbage

          相似的,**kwargs允許你使用沒有事先定義的參數(shù)名:

          >>> def table_things(**kwargs):
          ...    for name, value in kwargs.items():
          ...        print '{0} = {1}'.format(name, value)
          ...
          >>> table_things(apple = 'fruit', cabbage = 'vegetable')
          cabbage = vegetable
          apple = fruit

          你也可以混著用.命名參數(shù)首先獲得參數(shù)值然后所有的其他參數(shù)都傳遞給*args和**kwargs.命名參數(shù)在列表的最前端.例如:

          def table_things(titlestring, **kwargs)

          *args和**kwargs可以同時在函數(shù)的定義中,但是*args必須在**kwargs前面.


          當調(diào)用函數(shù)時你也可以用*和**語法.例如:

          >>> def print_three_things(a, b, c):
          ...    print 'a = {0}, b = {1}, c = {2}'.format(a,b,c)
          ...
          >>> mylist = ['aardvark', 'baboon', 'cat']
          >>> print_three_things(*mylist)

          a = aardvark, b = baboon, c = cat

          就像你看到的一樣,它可以傳遞列表(或者元組)的每一項并把它們解包.注意必須與它們在函數(shù)里的參數(shù)相吻合.當然,你也可以在函數(shù)定義或者函數(shù)調(diào)用時用*.


          http://stackoverflow.com/questions/3394835/args-and-kwargs


          11 面向切面編程AOP和裝飾器


          這個AOP一聽起來有點懵,同學面阿里的時候就被問懵了…


          裝飾器是一個很著名的設(shè)計模式,經(jīng)常被用于有切面需求的場景,較為經(jīng)典的有插入日志、性能測試、事務處理等。裝飾器是解決這類問題的絕佳設(shè)計,有了裝飾器,我們就可以抽離出大量函數(shù)中與函數(shù)功能本身無關(guān)的雷同代碼并繼續(xù)重用。概括的講,裝飾器的作用就是為已經(jīng)存在的對象添加額外的功能。


          這個問題比較大,推薦: http://stackoverflow.com/questions/739654/how-can-i-make-a-chain-of-function-decorators-in-python


          中文: http://taizilongxu.gitbooks.io/stackoverflow-about-python/content/3/README.html


          12 鴨子類型


          “當看到一只鳥走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那么這只鳥就可以被稱為鴨子?!?/p>


          我們并不關(guān)心對象是什么類型,到底是不是鴨子,只關(guān)心行為。


          比如在python中,有很多file-like的東西,比如StringIO,GzipFile,socket。它們有很多相同的方法,我們把它們當作文件使用。


          又比如list.extend()方法中,我們并不關(guān)心它的參數(shù)是不是list,只要它是可迭代的,所以它的參數(shù)可以是list/tuple/dict/字符串/生成器等.


          鴨子類型在動態(tài)語言中經(jīng)常使用,非常靈活,使得python不想java那樣專門去弄一大堆的設(shè)計模式。


          13 Python中重載


          引自知乎:http://www.zhihu.com/question/20053359


          函數(shù)重載主要是為了解決兩個問題。


          1. 可變參數(shù)類型。

          2. 可變參數(shù)個數(shù)。


          另外,一個基本的設(shè)計原則是,僅僅當兩個函數(shù)除了參數(shù)類型和參數(shù)個數(shù)不同以外,其功能是完全相同的,此時才使用函數(shù)重載,如果兩個函數(shù)的功能其實不同,那么不應當使用重載,而應當使用一個名字不同的函數(shù)。


          好吧,那么對于情況 1 ,函數(shù)功能相同,但是參數(shù)類型不同,python 如何處理?答案是根本不需要處理,因為 python 可以接受任何類型的參數(shù),如果函數(shù)的功能相同,那么不同的參數(shù)類型在 python 中很可能是相同的代碼,沒有必要做成兩個不同函數(shù)。


          那么對于情況 2 ,函數(shù)功能相同,但參數(shù)個數(shù)不同,python 如何處理?大家知道,答案就是缺省參數(shù)。對那些缺少的參數(shù)設(shè)定為缺省參數(shù)即可解決問題。因為你假設(shè)函數(shù)功能相同,那么那些缺少的參數(shù)終歸是需要用的。


          好了,鑒于情況 1 跟 情況 2 都有了解決方案,python 自然就不需要函數(shù)重載了。


          14 新式類和舊式類


          這個面試官問了,我說了老半天,不知道他問的真正意圖是什么.


          stackoverflow(http://stackoverflow.com/questions/54867/what-is-the-difference-between-old-style-and-new-style-classes-in-python)


          這篇文章很好的介紹了新式類的特性: http://www.cnblogs.com/btchenguang/archive/2012/09/17/2689146.html


          新式類很早在2.2就出現(xiàn)了,所以舊式類完全是兼容的問題,Python3里的類全部都是新式類.這里有一個MRO問題可以了解下(新式類是廣度優(yōu)先,舊式類是深度優(yōu)先),<Python核心編程>里講的也很多.


          15 __new__和__init__的區(qū)別


          這個__new__確實很少見到,先做了解吧.


          1. __new__是一個靜態(tài)方法,而__init__是一個實例方法.

          2. __new__方法會返回一個創(chuàng)建的實例,而__init__什么都不返回.

          3. 只有在__new__返回一個cls的實例時后面的__init__才能被調(diào)用.

          4. 當創(chuàng)建一個新實例時調(diào)用__new__,初始化一個實例時用__init__.


          stackoverflow(http://stackoverflow.com/questions/674304/pythons-use-of-new-and-init)


          ps: __metaclass__是創(chuàng)建類時起作用.所以我們可以分別使用__metaclass__,__new__和__init__來分別在類創(chuàng)建,實例創(chuàng)建和實例初始化的時候做一些小手腳.


          16 單例模式


          這個絕對??及?絕對要記住1~2個方法,當時面試官是讓手寫的.


          1 使用__new__方法

          class Singleton(object):
             def __new__(cls, *args, **kw):
                 if not hasattr(cls, '_instance'):
                     orig = super(Singleton, cls)
                     cls._instance = orig.__new__(cls, *args, **kw)
                 return cls._instance

          class MyClass(Singleton):
             a = 1

          2 共享屬性


          創(chuàng)建實例時把所有實例的__dict__指向同一個字典,這樣它們具有相同的屬性和方法.

          class Borg(object):
             _state = {}
             def __new__(cls, *args, **kw):
                 ob = super(Borg, cls).__new__(cls, *args, **kw)
                 ob.__dict__ = cls._state
                 return ob

          class MyClass2(Borg):
             a = 1

          3 裝飾器版本

          def singleton(cls, *args, **kw):
             instances = {}
             def getinstance():
                 if cls not in instances:
                     instances[cls] = cls(*args, **kw)
                 return instances[cls]
             return getinstance

          @singleton
          class MyClass:
           ...

          4 import方法


          作為python的模塊是天然的單例模式

          # mysingleton.py
          class My_Singleton(object):
             def foo(self):
                 pass

          my_singleton = My_Singleton()

          # to use
          from mysingleton import my_singleton

          my_singleton.foo()

          17 Python中的作用域


          Python 中,一個變量的作用域總是由在代碼中被賦值的地方所決定的。


          當 Python 遇到一個變量的話他會按照這樣的順序進行搜索:


          本地作用域(Local)→當前作用域被嵌入的本地作用域(Enclosing locals)→全局/模塊作用域(Global)→內(nèi)置作用域(Built-in)


          18 GIL線程全局鎖


          線程全局鎖(Global Interpreter Lock),即Python為了保證線程安全而采取的獨立線程運行的限制,說白了就是一個核只能在同一時間運行一個線程.


          見Python 最難的問題(http://www.oschina.net/translate/pythons-hardest-problem)


          解決辦法就是多進程和下面的協(xié)程(協(xié)程也只是單CPU,但是能減小切換代價提升性能).


          19 協(xié)程


          知乎被問到了,呵呵噠,跪了


          簡單點說協(xié)程是進程和線程的升級版,進程和線程都面臨著內(nèi)核態(tài)和用戶態(tài)的切換問題而耗費許多切換時間,而協(xié)程就是用戶自己控制切換的時機,不再需要陷入系統(tǒng)的內(nèi)核態(tài).


          Python里最常見的yield就是協(xié)程的思想!可以查看第九個問題.


          20 閉包


          閉包(closure)是函數(shù)式編程的重要的語法結(jié)構(gòu)。閉包也是一種組織代碼的結(jié)構(gòu),它同樣提高了代碼的可重復使用性。


          當一個內(nèi)嵌函數(shù)引用其外部作作用域的變量,我們就會得到一個閉包. 總結(jié)一下,創(chuàng)建一個閉包必須滿足以下幾點:


          1. 必須有一個內(nèi)嵌函數(shù)

          2. 內(nèi)嵌函數(shù)必須引用外部函數(shù)中的變量

          3. 外部函數(shù)的返回值必須是內(nèi)嵌函數(shù)


          感覺閉包還是有難度的,幾句話是說不明白的,還是查查相關(guān)資料.


          重點是函數(shù)運行后并不會被撤銷,就像16題的instance字典一樣,當函數(shù)運行完后,instance并不被銷毀,而是繼續(xù)留在內(nèi)存空間里.這個功能類似類里的類變量,只不過遷移到了函數(shù)上.


          閉包就像個空心球一樣,你知道外面和里面,但你不知道中間是什么樣.


          21 lambda函數(shù)


          其實就是一個匿名函數(shù),為什么叫l(wèi)ambda?因為和后面的函數(shù)式編程有關(guān).


          推薦: 知乎(http://www.zhihu.com/question/20125256)


          22 Python函數(shù)式編程


          這個需要適當?shù)牧私庖幌掳?畢竟函數(shù)式編程在Python中也做了引用.


          推薦: 酷殼(http://coolshell.cn/articles/10822.html)


          python中函數(shù)式編程支持:


          filter 函數(shù)的功能相當于過濾器。調(diào)用一個布爾函數(shù)bool_func來迭代遍歷每個seq中的元素;返回一個使bool_seq返回值為true的元素的序列。

          >>>a = [1,2,3,4,5,6,7]
          >>>b = filter(lambda x: x > 5, a)
          >>>print b
          >>>[6,7]

          map函數(shù)是對一個序列的每個項依次執(zhí)行函數(shù),下面是對一個序列每個項都乘以2:

          >>> a = map(lambda x:x*2,[1,2,3])
          >>> list(a)
          [2, 4, 6]

          reduce函數(shù)是對一個序列的每個項迭代調(diào)用函數(shù),下面是求3的階乘:

          >>> reduce(lambda x,y:x*y,range(1,4))
          6


          23 Python里的拷貝


          引用和copy(),deepcopy()的區(qū)別

          import copy
          a = [1, 2, 3, 4, ['a', 'b']]  #原始對象

          b = a  #賦值,傳對象的引用
          c = copy.copy(a)  #對象拷貝,淺拷貝
          d = copy.deepcopy(a)  #對象拷貝,深拷貝

          a.append(5)  #修改對象a
          a[4].append('c')  #修改對象a中的['a', 'b']數(shù)組對象

          print 'a = ', a
          print 'b = ', b
          print 'c = ', c
          print 'd = ', d

          輸出結(jié)果:
          a =  [1, 2, 3, 4, ['a', 'b', 'c'], 5]
          b =  [1, 2, 3, 4, ['a', 'b', 'c'], 5]
          c =  [1, 2, 3, 4, ['a', 'b', 'c']]
          d =  [1, 2, 3, 4, ['a', 'b']]


          24 Python垃圾回收機制


          Python GC主要使用引用計數(shù)(reference counting)來跟蹤和回收垃圾。在引用計數(shù)的基礎(chǔ)上,通過“標記-清除”(mark and sweep)解決容器對象可能產(chǎn)生的循環(huán)引用問題,通過“分代回收”(generation collection)以空間換時間的方法提高垃圾回收效率。


          1 引用計數(shù)


          PyObject是每個對象必有的內(nèi)容,其中ob_refcnt就是做為引用計數(shù)。當一個對象有新的引用時,它的ob_refcnt就會增加,當引用它的對象被刪除,它的ob_refcnt就會減少.引用計數(shù)為0時,該對象生命就結(jié)束了。


          優(yōu)點:


          1. 簡單

          2. 實時性


          缺點:


          1. 維護引用計數(shù)消耗資源

          2. 循環(huán)引用


          2 標記-清除機制


          基本思路是先按需分配,等到?jīng)]有空閑內(nèi)存的時候從寄存器和程序棧上的引用出發(fā),遍歷以對象為節(jié)點、以引用為邊構(gòu)成的圖,把所有可以訪問到的對象打上標記,然后清掃一遍內(nèi)存空間,把所有沒標記的對象釋放。


          3 分代技術(shù)


          分代回收的整體思想是:將系統(tǒng)中的所有內(nèi)存塊根據(jù)其存活時間劃分為不同的集合,每個集合就成為一個“代”,垃圾收集頻率隨著“代”的存活時間的增大而減小,存活時間通常利用經(jīng)過幾次垃圾回收來度量。


          Python默認定義了三代對象集合,索引數(shù)越大,對象存活時間越長。


          舉例:

          當某些內(nèi)存塊M經(jīng)過了3次垃圾收集的清洗之后還存活時,我們就將內(nèi)存塊M劃到一個集合A中去,而新分配的內(nèi)存都劃分到集合B中去。當垃圾收集開始工作時,大多數(shù)情況都只對集合B進行垃圾回收,而對集合A進行垃圾回收要隔相當長一段時間后才進行,這就使得垃圾收集機制需要處理的內(nèi)存少了,效率自然就提高了。在這個過程中,集合B中的某些內(nèi)存塊由于存活時間長而會被轉(zhuǎn)移到集合A中,當然,集合A中實際上也存在一些垃圾,這些垃圾的回收會因為這種分代的機制而被延遲。


          25 Python的List


          推薦: http://www.jianshu.com/p/J4U6rR


          26 Python的is


          is是對比地址,==是對比值


          27 read,readline和readlines


          • read 讀取整個文件

          • readline 讀取下一行,使用生成器方法

          • readlines 讀取整個文件到一個迭代器以供我們遍歷


          28 Python2和3的區(qū)別


          推薦:

          《Python 2.7.x 和 3.x 版本的重要區(qū)別》(http://python.jobbole.com/80006/)

          瀏覽 58
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  超碰国产97 | 台湾成人综合 | 香蕉色色网站 | 黄色视频在线观看地址 | 一区二区三区国产视频 |