1. 程式人生 > >公眾號上看到的python面試題10坑

公眾號上看到的python面試題10坑

問題1:請問如何修改以下Python程式碼,使下面的程式碼呼叫類A的show方法?

class A(object):
    def show(self):
        print('base show')

class B(A):
    def show(self):
        print('derived show')

obj = B()
obj.show()

答:題目問的是呼叫類A的show方法,不單單只是顯示A中的show的內容,所以要通過class方法指定到A的類物件即可:

obj.__class__ = A
obj.show()

問題2:請問如何修改以下Python程式碼,使得程式碼能夠執行?

class A(object):
    def __init__(self, a, b):
        self.__a = a
        self.__b = b
    def myprint(self):
        print('a=', self.__a, 'b=', self.__b)

a1 = A(10, 20)
a1.myprint()

a1(80)

答:該程式執行報了一個錯誤

Traceback (most recent call last):
('a=', 10, 'b=', 20)
  File "C:/Users/Lee/PycharmProjects/print/exeses.py", line 11, in <module>
    a1(80)
TypeError: 'A' object is not callable

這個錯誤的大致意思是將A類當成了一個方法來進行呼叫是不可行的。為了讓物件例項能被直接呼叫,需要實現call方法。

#-*- coding:utf-8 -*-
class A(object):
    def __init__(self, a, b):
        self.__a = a
        self.__b = b
    def myprint(self):
        print('a=', self.__a, 'b=', self.__b)
    def __call__(self, num):#num傳入
        print('call:', num + self.__a)#隨意讓num做一些事

a1 = A(10, 20)
a1.myprint()

a1(80)

結果

('a=', 10, 'b=', 20)
('call:', 90)

問題3:下面這段程式碼的輸出是什麼?

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', a)
        if a > 10:
            return super(A, cls).__new__(cls)
        return B()

    def __init__(self, a):
        print('INIT', a)

a1 = A(5)
a1.fn()
a2 = A(20)
a2.fn()
答:該題的關鍵點在於__new__方法。__init__其實不是例項化一個類的時候第一個被呼叫 的方法。當使用 a1 = A(5) 這樣的表示式來例項化一個類時,最先被呼叫的方法 其實是 __new__ 方法。所以很自然的,第一行輸出為NEW 5.接著判斷a是否大於10,此時a = 5,所以執行return B(),進入B類中執行;所以第二行和第三行是B類例項的呼叫B INIT, B fn。隨後新建一個a2的類例項,將a = 20傳入A類,先執行__new__,所以第四行是NEW 20,此時a大於了10,執行
return super(A, cls).__new__(cls)

大致的意思是得到當前類的例項(如果要得到當前類的例項,應當在當前類中的__new__()方法語句中呼叫當前類的父類 的__new__()方法)

所以還是例項還是在A中,第五行輸出INIT 20,接著呼叫A類中的fn方法,輸出A fn。最終結果

('NEW', 5)
B INIT
B fn
('NEW', 20)
('INIT', 20)
A fn

問題4:下面這段程式碼輸出什麼?

ls = [1, 2, 3, 4]
list1 = [i for i in ls if i > 2]
print(list1)

list2 = [i * 2 for i in ls if i > 2]
print(list2)

dic1 = {x: x ** 2 for x in (2, 4, 6)}
print(dic1)

set1 = {x for x in 'hello world' if x not in 'low level'}
print(set1)

答:該題考查列表解析和字典還有集合的生成方法。輸出如下:

[3, 4]
[6, 8]
{2: 4, 4: 16, 6: 36}
set(['h', 'r', 'd'])

問題5:下面這段程式碼輸出什麼?

num = 9

def f1():
    num = 20

def f2():
    print(num)

f2()
f1()
f2()

答:該題考查全域性變數和區域性變數的知識。先定義一個num = 9的全域性變數,接著在f1中定義了num = 20.由於區域性變數只能在當前定義的函式或者類中被呼叫,而全域性變數可以在任何函式或者類中被呼叫,前提是沒有被同名的區域性變數所覆蓋。所以該題的答案很明顯了,呼叫f2,print num 應該是全域性變數的num = 9,f1中的num  f2函式無法呼叫;接著呼叫f1,沒有print,所以無輸出;最後再一次呼叫f2,f1中的num = 20 並不能直接改變全域性變數的值,所以輸出9.要想在區域性變數中修改全域性變數的值,需要使用global

num = 9

def f1():
    global num
    num = 20

def f2():
    print(num)

f2()
f1()
f2()

這樣num就被修改為了20

9
20

問題6:如何使用一行程式碼交換兩個變數的值?

a = 8
b = 9

答:

(a, b) = (b, a)

問題7:如何新增程式碼,使得沒有定義的方法都呼叫mydefault方法?

class A(object):
    def __init__(self, a, b):
        self.a1 = a
        self.b1 = b
        print('init')
        
    def mydefault(self):
        print('default')
        
a1 = A(10, 20)
a1.fn1()
a1.fn2()
a1.fn3()
答:可以使用__getattr__方法解決這個問題,__getattr__函式的作用: 如果屬性查詢(attribute lookup)在例項以及對應的類中(通過__dict__)失敗, 那麼會呼叫到類的__getattr__函式, 如果沒有定義這個函式,那麼丟擲AttributeError異常。由此可見,__getattr__一定是作用於屬性查詢的最後一步,兜底。
class A(object):
    def __init__(self, a, b):
        self.a1 = a
        self.b1 = b
        print('init')

    def mydefault(self, *args):
        print('default')
    
    def __getattr__(self, item):
        return self.mydefault()#指向mydefault方法
        

a1 = A(10, 20)
a1.fn1()
a1.fn2()
a1.fn3()
這樣就就不會觸發異常了。還可以給mydefault方法增加一個*args不定引數來相容。

問題8:一個包裡有三個模組,mod1,py, mod2.py, mod3.py, 但使用from demopack import * 匯入模組時,如何保證只有mod1, mod3被匯入了?

答:在包中init.py檔案,並在檔案中增加:

__all__ = ['mod1', 'mod3']

python模組中的__all__w屬性,可用於模組匯入時限制,此時被匯入模組若定義了__all__屬性,則只有__all__內指定的屬性、方法、類可被匯入。

若沒定義,則匯入模組內的所有公有屬性,方法和類 。

問題9:寫一個函式,接收整數引數n,返回一個函式,函式返回n和引數的積。

def f1(n):
    def f2(x):
        return n * x
    return f2

num = f1(3)
print(num(9))

問題10:請問下面的程式碼有什麼隱患?

def strtest1(num):
    str = 'first'
    for i in range(num):
        str += 'x'
    return str
答:由於變數str是個不可變物件,每次迭代,Python都會生成新的str物件來儲存新的字串,num越大,建立的str物件越多,記憶體消耗越大。