「Python 面試」第二次更新

圖片描述

閱讀本文大約須要 8 分鐘。

7.說一下 Python 中的裝飾器

原理:利用閉包,將目標函數外面再套一層函數,使得目標函數具備一個新的功能,而且不改變目標函數原有功能。 算法

實現方式:多線程

  1. 閉包閉包

    def decorate(func):
        def wrapper():
            print('新功能')
            func()    
        return wrapper
    
    def func():
        print('原有功能')
    
    f = decorate(func)
    f()
    
    # 結果爲:
    新功能
    原有功能
  2. @ 語法糖app

    def decorate01(func):
        def wrapper():
            print('新功能')
            func()       
        return wrapper
    
    @decorate01
    def func01():
        print("原有功能")
    
    func01()
    
    # 結果爲:
    新功能
    原有功能

8.說一說類屬性、實例屬性、私有屬性和保護屬性

類屬性至關於所有變量,全部由類建立出來的實例,均可以使用,而實例屬性至關於局部變量,只能由該實例本身使用,當類屬性與實例屬性命名同樣時,在調用該同名屬性時,會屏蔽掉類屬性,調用實例屬性,這點跟 LEGB 很像。函數

當經過實例對象來修改類屬性時,其實修改的並非類屬性,而是新建了一個跟類屬性名同樣的實例屬性。性能

Python 中將以兩個下劃線__開頭,但不以兩個下劃線結尾的變量,認做爲私有屬性,Python 經過 name manage算法,將該私有屬性的引用更改成_classname_reference,用戶試圖調用該私有屬性時,會由於對象引用不同而找不到該屬性,故而實現了「屬性私有化」。spa

在獲取實例屬性時,通常採用定義一個實例方法的方式獲取屬性,避免直接對實例屬性進行操做,起到一個保護屬性的做用。線程

9.爲何說 Python 是動態語言,鴨子類型是指什麼

Python 至關於其餘靜態語言,能夠在代碼運行過程當中,改變變量的屬性。code

鴨子類型指的是 Python 不用定義變量類型,只要該變量像是什麼類型,那麼就認爲它就是什麼類型,咱們更多關注的是它的行爲,而不是它的類型。協程

10.元類是什麼

實例都是由類建立出來,而類則是由元類建立出來。他們之間的關係至關於「奶奶-媽媽-孫子」。

示例:

class Myclass():
    pass


new = type('NewClass', (Myclass,), {'name': 'new'})

print(new)
print(new.__mro__)  # 查看該類的繼承狀況

# 結果爲
<class '__main__.NewClass'>
(<class '__main__.NewClass'>, <class '__main__.Myclass'>, <class 'object'>)

具體點的內容能夠參考這篇問答:什麼是元類

11.@staticmethod 和 @classmethod 的區別

@staticmethod 是爲類添加一個靜態方法

@classmethod 是爲類添加一個類方法

12.如何動態添加屬性

因爲 Python 的特性使得程序在運行過程當中,咱們能夠爲某個對象添加屬性、方法。

示例:

class Myclass:
    pass


m = Myclass()

# 爲實例動態添加一個屬性
m.name = 'new_atribute'

def func(self):
    return 'new_function'

# 爲實例動態添加一個方法
m.func = func

print(m.name)
print(m.__dict__) # 返回 m 的全部屬性,方法

# 結果爲
new_atribute
new_function
{'func': <function func at 0x7f9452be12f0>, 'name': 'new_atribute'}

# 另一種動態添加方法
import types


def func01(self):
    print('new_function01')

# 實例 m 添加一個屬性 func,而這個屬性指向func()函數,故當調用 m.func 時,也就至關於調用了 func() 函數,間接實現了爲 m 添加方法 func()。
m.func = types.MethodType(func, m)

print(m.func())

# 結果爲 new_function01

13.對於迭代器和生成器你知道哪些,它們分別應用於什麼場景

先介紹什麼是可迭代的Iterable:任何可用於for循環的都是可迭代的。也可使用collection模塊下的isinstance(obj, Iterable)來檢驗該對象是否可迭代。

示例:

from collections import Iterable


print(isinstance('abc',Iterable)) 
print(isinstance(123,Iterable)) 

# 結果爲 True,False
  • 迭代器

    任何可使用next()函數的都是迭代器,也可以使用iter()函數將可迭代對象變爲迭代器。

    示例:

    from collections import Iterator
    
    
    itr = iter('abc')
    
    print(type(itr))
    print(isinstance(itr, Iterator)) 
    
    # 結果爲 Iterator,True
  • 生成器

    任何函數中含有yield關鍵字的都是生成器,列表生成式中的[]改成()也是一個生成器。

    • 實現方式

      示例:

      g = [i for i in range(10)]
      
      print(type(g))
      
      # 結果爲 list
      
      g1 = (i for i in range(10))
      
      print(type(g1))
      
      # 結果爲 generator
      
      def func():
          for i in range(10):
              yield i
      
      f = func()
      print(f)
      
      # 結果爲 <generator object func at 0x7f92f5294048>
    • 生成器怎麼取值,何時結束

      生成器能夠經過next(f)f.__next__()f.send()三種方式來取值

      示例:

      def func01():
          for i in range(10):
              yield i
      
      f = func()
      print(next(f))
      print(f.__next__())
      print(f.send('hahah'))
      
      # 結果爲 
      0
      1
      2

      其中f.send()能夠向生成器傳值,可是其第一次傳入的值默認爲None。若是想要取出send('hahah')裏傳入的值,則須要在生成器中添加接收的變量。

      示例:

      def func():
          for i in range(10):
              # yield i
              temp = yield i
              print(temp)
              
      f = func()
      
      print(next(f))
      print(f.__next__())
      print(f.send('hahah'))  
      
      # 結果爲
      0
      None
      1
      hahah
      2

      生成器裏的值被取完以後,或者中間遇到 return關鍵字,就會退出,這三種方法有一個共同點:當生成器取完以後會拋出StopIteration的錯誤。

      而使用for循環來取出生成器裏的值就不會拋出錯誤,這也是最被推薦的。

    • 應用場景

      在生成一個包含不少數(百萬級別)的列表時,可是又只用獲得其中很小一部分的數時,使用列表生成式會極大的浪費內存,且不必定可以生成,由於受機器內存限制。

      而使用生成器則否則,生成器只是在你須要的時候,纔會申請一塊內存,能夠邊取邊用,極大的下降了內存消耗。

      生成器用的最多的地方在於「協程」。因爲基於 C 解釋器下的 Python 中含有一個 GIL 鎖,使得 Pyhon 的多線程是一個假性多線程,這也是爲何不少人說 Python 性能慢的緣由。


未寫完,下次更新補上。

相關文章
相關標籤/搜索