Python 精选笔试面试习题—类继承、方法对象、包管理、闭包、可变类型作为默认参数、列表引用、sort与sorted、 append 和 extend、深拷贝和浅拷贝
1. 類繼承
如下代碼
class A(object):def show(self):print 'This is calss A'class B(A):def show(self):print 'This is calss B'obj = B()
obj.show()
如何才能調用類 A 的 show 方法呢?
obj.__class__ = A
obj.show()
__ class __ 方法指向了類對象,只用給他賦值類型 A,然后調用方法 show,但是用完了記得修改回來。
2. 方法對象
問題:為了讓下面這段代碼運行,需要增加哪些代碼?
class A(object):def __init__(self,a,b):self.__a = aself.__b = bdef myprint(self):print 'a=', self.__a, 'b=', self.__ba1=A(10,20)
a1.myprint()a1(80)
答案:為了能讓對象實例能被直接調用,需要實現__ call __ 方法
class A(object):def __init__(self, a, b):self.__a = aself.__b = bdef myprint(self):print 'a=', self.__a, 'b=', self.__bdef __call__(self, num):print 'call:', num + self.__a
3. __ new __ 和 __ init __
下面這段代碼輸出什么?
class B(object):def fn(self):print 'B fn'def __init__(self):print "B INIT"class A(object):def fn(self):print 'A fn'def __new__(cls,a):print "NEW", aif a>10:return super(A, cls).__new__(cls)return B()def __init__(self,a):print "INIT", aa1 = A(5)
a1.fn()
a2=A(20)
a2.fn()
輸出結果:
NEW 5
B INIT
B fn
NEW 20
INIT 20
A fn
使用__ new __ 方法,可以決定返回那個對象,也就是創建對象之前,這個可以用于設計模式的單例、工廠模式。__ init __ 是創建對象是調用的。
4. 默認方法
如下代碼:
class A(object):def __init__(self,a,b):self.a1 = aself.b1 = bprint 'init'def mydefault(self):print 'default'a1 = A(10,20)
a1.fn1()
a1.fn2()
a1.fn3()
方法 fn1/fn2/fn3 都沒有定義,怎樣修改代碼,使得沒有定義的方法都調用 mydefault 函數,上面的代碼應該輸出
default
default
default
答案如下:
class A(object):def __init__(self,a,b):self.a1 = aself.b1 = bprint 'init'def mydefault(self):print 'default'def __getattr__(self,name):return self.mydefaulta1 = A(10,20)
a1.fn1()
a1.fn2()
a1.fn3()
方法__ getattr __ 只有當沒有定義的方法調用時,才是調用他。當 fn1 方法傳入參數時,我們可以給mydefault 方法增加一個 *args 不定參數來兼容。
class A(object):def __init__(self,a,b):self.a1 = aself.b1 = bprint 'init'def mydefault(self,*args):print 'default:' + str(args[0])def __getattr__(self,name):print "other fn:",namereturn self.mydefaulta1 = A(10,20)
a1.fn1(33)
a1.fn2('hello')
a1.fn3(10)
輸出結果如下:
init
other fn: fn1
default:33
other fn: fn2
default:hello
other fn: fn3
default:10
5. 包管理
一個包里有三個模塊,mod1.py, mod2.py, mod3.py,但使用 from demopack import * 導入模塊時,如何保證只有 mod1、mod3 被導入了。
答案:增加__ init __.py 文件,并在文件中增加:
__all__ = ['mod1','mod3']
6. 閉包
寫一個函數,接收整數參數n,返回一個函數,函數的功能是把函數的參數和n相乘并把結果返回。
In [8]: def fun(n):...: def g(val):...: return n * val...: return g...: ...: ff = fun(7)...: print(ff(9))...:
63
7. 可變類型作為函數默認參數
下面代碼輸出結果是什么?
def extendList(val, list=[]):list.append(val)return listlist1 = extendList(10)
list2 = extendList(123,[])
list3 = extendList('a')print "list1 = %s" % list1
print "list2 = %s" % list2
print "list3 = %s" % list3
輸出結果為:
list1 = [10, 'a']
list2 = [123]
list3 = [10, 'a']
很多人都會誤認為 list1=[10], list3=[‘a’],因為他們以為每次 extendList 被調用時,列表參數的默認值都將被設置為[].但實際上的情況是,新的默認列表只在函數被定義的那一刻創建一次。當 extendList 被沒有指定特定參數list調用時,這組list的值隨后將被使用。這是因為帶有默認參數的表達式在函數被定義的時候被計算,不是在調用的時候被計算。
因此 list1 和 list3 是在同一個默認列表上進行操作(計算)的。而 list2 是在一個分離的列表上進行操作(計算)的。(通過傳遞一個自有的空列表作為列表參數的數值)。
extendList 的定義可以作如下修改。盡管,創建一個新的列表,沒有特定的列表參數。
下面這段代碼可能能夠產生想要的結果。
def extendList(val, list=None):if list is None:list = []list.append(val)return list
通過上面的修改,輸出結果將變成:
list1 = [10]
list2 = [123]
list3 = ['a']
8. 超出成員個數的切片
下面代碼輸出的結果是什么?
list = ['a', 'b', 'c', 'd', 'e']
print list[10:]
輸出結果為:
[]
例如,嘗試獲取list[10]和之后的成員,會導致 IndexError。
然而,嘗試獲取列表的切片,開始的index超過了成員個數不會產生 IndexError,而是僅僅返回一個空列表。
這成為特別讓人惡心的疑難雜癥,因為運行的時候沒有錯誤產生,導致bug很難被追蹤到。
9. 列表的引用
有以下代碼
1. list = [ [ ] ] * 5
2. list # output?
3. list[0].append(10)
4. list # output?
5. list[1].append(20)
6. list # output?
7. list.append(30)
8. list # output?
2,4,6,8行的輸出結果如下:
[[], [], [], [], []]
[[10], [10], [10], [10], [10]]
[[10, 20], [10, 20], [10, 20], [10, 20], [10, 20]]
[[10, 20], [10, 20], [10, 20], [10, 20], [10, 20], 30]
原因如下:
第一行的輸出結果直覺上很容易理解,例如 list = [ [ ] ] * 5 就是簡單的創造了5個空列表。
然而,理解表達式list=[ [ ] ] * 5的關鍵一點是它不是創造一個包含五個獨立列表的列表,而是它是一個創建了包含對同一個列表五次引用的列表。
只有了解了這一點,我們才能更好的理解接下來的輸出結果。
list[0].append(10) 將10附加在第一個列表上。
但由于所有5個列表是引用的同一個列表,所以這個結果將是:
[[10], [10], [10], [10], [10]]
同理,list[1].append(20)將20附加在第二個列表上。但同樣由于5個列表是引用的同一個列表,所以輸出結果現在是:
[[10, 20], [10, 20], [10, 20], [10, 20], [10, 20]]
作為對比, list.append(30)是將整個新的元素附加在外列表上,因此產生的結果是:
[[10, 20], [10, 20], [10, 20], [10, 20], [10, 20], 30]
10. L.sort() 與 sorted() 的區別
L.sort(cmp=None, key=None, reverse=False)sorted(iterable, cmp=None, key=None, reverse=False)
- L.sort():該函數的三個參數和 sorted() 的后三個參數含義是一致的,而需要特別注意的是,該函數只適用于列表,而非任意可以迭代的對象。cmp 是比較函數,接受兩個對象參數 x 和 y,返回 負數(x<y),0(x=y),正數(x>y)。
- 該函數第一個參數 iterable 為任意可以迭代的對象,cmp 是比較函數,通常為lambda函數,key 是用于比較的關鍵字,reverse表示排序結果是否反轉。
In [10]: aa = [5,4,3,2,1]In [11]: aa.sort()In [12]: aa
Out[12]: [1, 2, 3, 4, 5]
調用 sort() 之后會改變原來的表的結構順序。
可以指定關鍵字排序
student = [['Tom', 'A', 20], ['Jack', 'C', 18], ['Andy', 'B', 11]]
student.sort(key=lambda student: student[2])## 輸出結果
[['Andy', 'B', 11], ['Jack', 'C', 18], ['Tom', 'A', 20]]
sorted() 可以應用于任意的可以迭代的對象,所以應用范圍比 L.sort() 廣泛的多,可以應用于字符串,元組,列表,字典等可迭代對象。
In [19]: s = "zyx"In [20]: sorted(s)
Out[20]: ['x', 'y', 'z']In [21]: s
Out[21]: 'zyx'
需要注意的是,該函數會返回一個排序后的列表,原有可迭代對象保持不變,這與 L.sort() 函數不同。然而,這會浪費較大的存儲空間,尤其是數據量較大時。所以,在列表進行排序時,需要考慮是否需要保存原列表,如果無需保存原列表,則優先使用L.sort() 節省內存空間,提高效率。
- L.sort() 函數只適用于列表排序,而sorted()函數適用于任意可以迭代的對象排序。
- L.sort() 函數排序會改變原有的待排序列表,而sorted()函數則不會改變。所以在使用列表進行排序時,需要考慮是否需要保存原列表,如果無需保存原列表,則優先使用L.sort() 節省內存空間,提高效率。
- 兩個函數通過定義 key 和 cmp 都可以完成排序,但是 key 的效率要遠遠高于 cmp,所以要優先使用 key 。
11. append 與 extend 方法有什么區別
append表示把某個數據當做新元素整體追加到列表的最后面,它的參數可以是任意對象。
extend 的參數必須是一個可迭代對象,表示把該對象里面的所有元素逐個地追加到列表的后面。
In [1]: x = [1,2,3]In [2]: y = [4,5]In [3]: x.append(y)In [4]: x
Out[4]: [1, 2, 3, [4, 5]]In [5]: x = [1,2,3]In [6]: x.extend(y)In [7]: x
Out[7]: [1, 2, 3, 4, 5]
12. 深拷貝與淺拷貝
- copy.copy 是淺拷貝,只會復制父對象,而不會復制對象內部的子對象;
- copy.deepcopy 是深拷貝,會復制對象及其子對象;
In [1]: import copyIn [2]: a = [1,2,3, ['a', 'b']]In [3]: b = aIn [4]: c = a[:]In [5]: d = copy.copy(a)In [6]: e = copy.deepcopy(a)In [7]: id(a)
Out[7]: 62660040LIn [8]: id(b)
Out[8]: 62660040LIn [9]: id(c)
Out[9]: 62660424LIn [10]: id(d)
Out[10]: 62519944LIn [11]: id(e)
Out[11]: 62520776L
通過 = 賦值,它的 id 是和 a 本身是一樣的;
通過 [:] 切片賦值和 copy.copy() 賦值的 id 是一樣的,它們都是淺拷貝;
通過 copy.deepcopy() 賦值的 id 是和其它都不一樣,它是深拷貝;為啥叫做深拷貝,看下面。
In [12]: a[0] = 'aaa'In [13]: a[3].append('c')In [14]: a
Out[14]: ['aaa', 2, 3, ['a', 'b', 'c']]In [15]: b
Out[15]: ['aaa', 2, 3, ['a', 'b', 'c']]In [16]: c
Out[16]: [1, 2, 3, ['a', 'b', 'c']]In [17]: d
Out[17]: [1, 2, 3, ['a', 'b', 'c']]In [18]: e
Out[18]: [1, 2, 3, ['a', 'b']]
參考:
http://www.bugcode.cn/PythonQuestions.html
https://segmentfault.com/a/1190000006265256
http://www.cnblogs.com/wilber2013/p/5178620.html
http://python.jobbole.com/86525/
http://www.cnblogs.com/wilber2013/p/4645353.html
http://www.cnblogs.com/Vito2008/p/5044251.html
總結
以上是生活随笔為你收集整理的Python 精选笔试面试习题—类继承、方法对象、包管理、闭包、可变类型作为默认参数、列表引用、sort与sorted、 append 和 extend、深拷贝和浅拷贝的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何读取比机器内存大的文件(内存4G,文
- 下一篇: 类似《天地传说》的影视剧是?