來源:老男孩IT

乾貨丨比延禧攻略還要猛的Python面試攻略



嗨談篇

1.*args和**kwargs是什麼意思?

答:*args表示可變參數(variadic arguments),它允許你傳入0個或任意個無名參數,這些參數在函數調用時自動組裝爲一個tuple; **kwargs表示關鍵字參數(keyword arguments),它允許你傳入0個或任意個含參數名的參數,這些關鍵字參數在函數內部自動組裝爲一個dict。同時使用*args和**kwargs的時候,必須保證*args在**kwargs之前。

擴展閱讀:

https://blog.csdn.net/mbugatti/article/details/53884455

2.python裏面如何拷貝一個對象?

答:

(1) 賦值(=),就是創建了對象的一個新的引用,修改其中任意一個變量都會影響到另一個;

(2)淺拷貝(copy.copy()),創建一個新的對象,但它包含的是對原始對象中包含項的引用(如果用引用的方式修改其中一個對象,另一個也會被改變);

(3)深拷貝(copy.deepcopy()),創建一個新的對象,並且遞歸的複製它所包含的對象(修改其中一個,另一個不會改變)

注意:並不是所有的對象都可以拷貝

擴展閱讀:

http://www.cnblogs.com/wilber2013/p/4645353.html

3.簡要描述python的垃圾回收機制

答:python中的垃圾回收是以引用計數爲主,標記-清除和分代收集爲輔。

引用計數:python在內存中存儲每個對象的引用計數,如果計數變成0,該對象就會消失,分配給該對象的內存就會釋放出來。

標記-清除:一些容器對象,比如說list、dict、tuple、instance等可能會出現引用循環,對於這些循環,垃圾回收器會定時回收這些循環(對象之間通過引用(指針)連在一起,構成一個有向圖,對象構成這個有向圖的節點,而引用關係構成這個有向圖的邊)。

分代收集:python把內存根據對象存活時間劃分爲三代,對象創建之後,垃圾回收器會分配它們所屬的代。每個對象都會被分配一個代,而被分配更年輕的代是被優先處理的,因此越晚創建的對象越容易被回收。

擴展閱讀:

https://www.jianshu.com/p/1e375fb40506

4.什麼是lambda函數?它有什麼好處?

答:lambda表達式,通常是在需要一個函數,但是又不想費神去命名一個函數的場合下使用,也就是指匿名函數。

Python允許你定義一種單行的小函數。定義lambda函數的形式如下(lambda參數:表達式)lambda函數默認返回表達式的值。你也可以將其賦值給一個變量。lambda函數可以接受任意個參數,包括可選參數,但是表達式只有一個。

擴展閱讀:

https://www.zhihu.com/question/20125256

5.python如何實現單例模式?

答:單例模式是一種常用的軟件設計模式。在它的核心結構中只包含一個被稱爲單例類的特殊類。通過單例模式可以保證系統中一個類只有一個單例而且該單例易於外界訪問,從而方便對實例個數的控制並節約系統資源。如果希望在系統中某個類的對象只能存在一個,單例模式是最好的解決方案。

__new__()在__init__()之前被調用,用於生成實例對象。利用這個方法和累的屬性的特點可以實現設計模式的單例模式。單例模式是指創建唯一對象,單例模式設計的類只能實例。

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.共享屬性

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方法

class My_Singleton(object):
def foo(self):
pass
my_singleton = My_Singleton()
# to use
from mysingleton import my_singleton
my_singleton.foo()

擴展閱讀:

https://blog.csdn.net/sirodeng/article/details/17426543

6.python自省

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

a = [1,2,3]
b = {'a':1,'b':2,'c':3}
c = True
print type(a),type(b),type(c) #
print isinstance(a,list) # True

擴展閱讀:

https://kb.cnblogs.com/page/87128/

7.談一談python的裝飾器

答:裝飾器本質上是一個python函數,它可以讓其他函數在不作任何變動的情況下增加額外功能,裝飾器的返回值也是一個函數對象。它經常用於有切面需求的場景。比如:插入日誌、性能測試,事務處理、緩存、權限驗證等。有了裝飾器我們就可以抽離出大量的與函數功能無關的雷同代碼進行重用。

擴展閱讀:

https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014318435599930270c0381a3b44db991cd6d858064ac0000

8.什麼是鴨子類型?

答:在鴨子類型中,關注的不是對象的類型本身,而是他如何使用的。例如,在不適用鴨子類型的語言中,我們可以編寫一個函數,它接受一個類型爲鴨的對象,並調用它的走和叫方法。在使用鴨子類型的語言中,這樣的一個函數可以接受一個任意類型的對象,並調用它的走和叫方法。

class duck():
def walk(self):
print('I am duck,I can walk...')
def swim(self):
print('I am duck,I can swim...')
def call(self):
print('I am duck,I can call...')
duck1=duck()
duck1.walk()
# I am duck,I can walk...
duck1.call() # I am duck,I can call...

擴展閱讀:

https://blog.csdn.net/handsomekang/article/details/40270009

9.@classmethod和@staticmethod

答:@classmethod修飾符對應的函數不需要實例化,不需要self參數,第一個參數需要是表示自身類的cls參數,cls參數可以用來調用類的屬性,類的方法,實例化對象等。@staticmethod返回函數的靜態方法,該方法不強制要求傳遞參數,如下聲明一個靜態方法:

Class C(object):

@staticmethod

Def f(arg1, arg2,…):

以上實例聲明瞭靜態方法f,類可以不用實例化就可以調用該方法C.f(),也可以實例化後調用C().f()。

擴展閱讀:

https://zhuanlan.zhihu.com/p/28010894

10.談一談python中的元類

答:一般來說,我們都是在代碼裏定義類,用定義的類來創建實例。而使用元類,步驟又是同,定義元類,用元類創建類,再使用創建出來的類來創建實例。元類的主要目的就是爲了當創建類時能夠自動地改變類。

擴展閱讀:

https://blog.csdn.net/wenyu826/article/details/66972933

請輸入標題 bcdef

本文參考文檔:

1. github“hackerxu”:關於Python的面試題

2. 知乎專欄“python爬蟲實戰”:python面試指南

3. 51CTO“老男孩python”:2018python面試必看的10個問題及答案

4. 老左的博客:python面試必須要看的15個問題

5. CSDN“劉元濤”:python工程師面試題集合

6. 知乎“路人甲”:常見的面試題整理——python概念篇

coding篇

1.臺階問題/斐波那契

一隻青蛙一次可以跳上1級臺階,也可以跳上2級。求該青蛙跳上一個n級的臺階總共有多少中跳法:

fib = lambda n: n if n <= 2 else fib(n - 1) + fib(n - 2)

第二種方法:

def memo(func):
cache = {}
def wrap(*args):
if args not in cache:
cache[args] = func(*args)
return cache[args]
return wrap
@memo
def fib(i):
if i < 2:
return 1
return fib(i-1) + fib(i-2)

第三種方法:

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

2.去除列表中的重複元素

用集合

list(set(l))

用字典

l1 = ['b','c','d','b','c','a','a']
l2 = {}.fromkeys(l1).keys()
print (l2)

列表推導

l1 = ['b','c','d','b','c','a','a']
l2 = []
[l2.append(i) for i in l1 if not i in l2]

3.合併兩個有序列表

尾遞歸

def _recursion_merge_sort2(l1, l2, tmp):
if len(l1) == 0 or len(l2) == 0:
tmp.extend(l1)
tmp.extend(l2)
return tmp
else:
if l1[0] < l2[0]:
tmp.append(l1[0])
del l1[0]
else:
tmp.append(l2[0])
del l2[0]
return _recursion_merge_sort2(l1, l2, tmp)
def recursion_merge_sort2(l1, l2):
return _recursion_merge_sort2(l1, l2, [])

循環算法

思路:

定義一個新的空列表

比較兩個列表的首個元素

小的就插入到新列表裏

把已經插入新列表的元素從舊列表刪除

直到兩個舊列表有一個爲空

再把舊列表加到新列表後面

def loop_merge_sort(l1, l2):
tmp = []
while len(l1) > 0 and len(l2) > 0:
if l1[0] < l2[0]:
tmp.append(l1[0])
del l1[0]
else:
tmp.append(l2[0])
del l2[0]
tmp.extend(l1)
tmp.extend(l2)
return tmp

pop彈出

a = [1,2,3,7]
b = [3,4,5]
def merge_sortedlist(a,b):
c = []
while a and b:
if a[0] >= b[0]:
c.append(b.pop(0))
else:
c.append(a.pop(0))
while a:
c.append(a.pop(0))
while b:
c.append(b.pop(0))
return c
print (merge_sortedlist(a,b))

4.二分查找

#coding:utf-8
def binary_search(list,item):
low = 0
high = len(list)-1
while low<=high:
mid = int((low+high)/2)
guess = list[mid]
if guess>item:
high = mid-1
elif guess low = mid+1
else:
return mid
return None
mylist = [1,3,5,7,9]
print (binary_search(mylist,3))

參考: http://blog.csdn.net/u013205877/article/details/76411718

5.快排

#coding:utf-8
def quicksort(list):
if len(list)<2:
return list
else:
midpivot = list[0]
lessbeforemidpivot = [i for i in list[1:] if i<=midpivot]
biggerafterpivot = [i for i in list[1:] if i > midpivot]
finallylist = quicksort(lessbeforemidpivot)+[midpivot]+quicksort(biggerafterpivot)
return finallylist
print (quicksort([2,4,6,7,1,2,5]))

參考:https://blog.csdn.net/mrlevo520/article/details/77829204

6.使用python實現單例模式

方法一:可以使用__new__方法

在__new__方法中把類實例綁定到類變量_instance上,如果cls._instance爲None表示該類還沒有實例化過,實例化該類並返回。如果cls_instance不爲None表示該類已實例化,直接返回cls_instance

class SingleTon(object):
def __new__(cls,*args,**kwargs):
if not hasattr(cls,'_instance'):
cls._instance = object.__new__(cls,*args,**kwargs)
return cls._instance
class TestClass(SingleTon):
a = 1
test1 = TestClass()
test2 = TestClass()
print (test1.a,test2.a)
test1.a=2
print (test1.a,test2.a)
print (id(test1),id(test2))

方法二:使用裝飾器,建立過實例的就放到instances裏面,下次建立的時候先檢查裏面有沒有

def SingleTon(cls,*args,**kwargs):
instances = {}
print (instances)
def _singleton():
if cls not in instances:
instances[cls] = cls(*args,**kwargs)
print (instances)
return instances[cls]
return _singleton
@SingleTon
class LastClass(object):
a = 1
test1 = LastClass()
print (test1.a)
test2 = LastClass()
print (test2.a)

方法三:使用__metaclass__(元類)關於元類看看這個吧:http://blog.jobbole.com/21351/

class SignalTon(type):
def __init__(cls,name,bases,dict):
super(SignalTon, cls).__init__(name,bases,dict)
cls._instance = None
def __call__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super(SignalTon,cls).__call__(*args,**kwargs)
return cls._instance
class TestClass(object):
__metaclass__ = SignalTon
test1 = TestClass()
test2 = TestClass()
test1.a = 2
print (test1.a,test2.a)
print (id(test1),id(test2))

方法四:共享屬性

所謂單例就是所有的引用(實例,對象)擁有相同的屬性和方法,同一個類的實例天生都會有相同的方法,那我們只需要保證同一個類所產生的實例都具有相同的屬性。所有實例共享屬性最簡單直接的方法就是共享__dict__屬性指向。

class SingleTon(object):
_state = {}
def __new__(cls, *args, **kwargs):
obj = object.__new__(cls,*args,**kwargs)
obj.__dict__ = cls._state
return obj
class TestClass(SingleTon):
a = 1
test1 = TestClass()
test2 = TestClass()
print (test1.a,test2.a)
test1.a = 2
print (test1.a,test2.a)
print (id(test1),id(test2))

方法五:使用同一個模版,寫在mysingleton.py中

class My_Singleton(object):
def foo(self):
pass
my_singleton = My_Singleton()
#寫在要使用這個實例的py文件裏面,在不同的引用的地方都引用相同的實例,以此實現單例模式
from mysingleton import my_singleton
my_singleton.foo()

7.前中後序遍歷

深度遍歷改變順序就好了

#coding:utf-8
#二叉樹的遍歷
#簡單的二叉樹節點類
class Node(object):
def __init__(self,value,left,right):
self.value = value
self.left = left
self.right = right
#中序遍歷:遍歷左子樹,訪問當前節點,遍歷右子樹
def mid_travelsal(root):
if root.left is None:
mid_travelsal(root.left)
#訪問當前節點
print(root.value)
if root.right is not None:
mid_travelsal(root.right)
#前序遍歷:訪問當前節點,遍歷左子樹,遍歷右子樹
def pre_travelsal(root):
print (root.value)
if root.left is not None:
pre_travelsal(root.left)
if root.right is not None:
pre_travelsal(root.right)
#後續遍歷:遍歷左子樹,遍歷右子樹,訪問當前節點
def post_trvelsal(root):
if root.left is not None:
post_trvelsal(root.left)
if root.right is not None:
post_trvelsal(root.right)
print (root.value)

8.super函數的原理

#閱讀下面的代碼,它的輸出結果是什麼?
class A(object):
def __init__(self):
print ("enter A")
super(A, self).__init__() # new
print ("leave A")
class B(object):
def __init__(self):
print ("enter B")
super(B, self).__init__() # new
print ("leave B")
class C(A):
def __init__(self):
print ("enter C")
super(C, self).__init__()
print ("leave C")
class D(A):
def __init__(self):
print ("enter D")
super(D, self).__init__()
print ("leave D")
class E(B, C):
def __init__(self):
print ("enter E")
super(E, self).__init__() # change
print ("leave E")
class F(E, D):
def __init__(self):
print ("enter F")
super(F, self).__init__() # change
print ("leave F")
#輸出
enter F
enter E
enter B
enter C
enter D
enter A
leave A
leave D
leave C
leave B
leave E
leave F
相關文章