記搜狗一次不成功的Python后端面試經歷


面試搜狗Python后端結束快一個月了,終於有時間來做一個簡單的總結了。

簡介:工作不久,基礎后端崗位,一面結束,失敗。

先做了幾個筆試題,面試開始會根據筆試題問一些內容。下面將整理一下還能想起來的內容。

1.一個代碼題,要求輸出的結果是什么,並解釋原因

def f(x, l=[]):
  for i in xrange(x):
      l.append(i**2)
  print l

f(2)  # [0, 1]
f(3, [3, 2, 1])  # [3, 2, 1, 0, 1, 4]
f(3)  # [0, 1, 0, 1, 4]

面試過程:輸出結果如上所示,當時我回答的原因是列表是可變對象,設置為函數的默認參數的時候,會保留值,應該默認設置為None這種類型。面試官又問為什么可變對象就不行呢?我回答在Python中函數也是一個對象,他的一個屬性會保存相應的默認值。

簡要總結:根據官方文檔,默認參數在定義的時候,只初始化一次。可以在函數對象的func_defaults屬性中查看默認參數。如下所示,通過把函數對象的默認參數的內存地址打印出來,可以看到確實是同一個列表地址。

print id(f.func_defaults[0])
f(2)
print id(f.func_defaults[0])
f(3, [3, 2, 1])
print id(f.func_defaults[0])
f(3)

2.*args 和 **kwargs 是什么,為什么要使用它們?

面試過程: 回答了前者是位置參數,后者是關鍵字參數,在函數定義時,參數不確定的情況下可以使用,是一個pack過程,在函數調用時,是一個unpack過程。

3.說一下Python的內存管理,說一下垃圾回收機制?

面試過程: 內存管理包括垃圾回收、引用計數、內存池,垃圾回收機制是引用計數為主、標記清除和分代回收為輔。然后我就用大白話解釋了一下我對這些內容的理解,導致說的比較尷尬。。

回顧總結: 關於內存管理,個人覺得這篇比較好,點擊鏈接,說的比較明白。垃圾回收的三種機制是互相關聯的,可以直接搜索找到合適自己的答案。

4.編程實現二分查找?

當時寫的代碼如下

def b_search(data, k):
    if not data:
        return -1
    left, right = 0, len(data) - 1
    while left <= right:
        mid = (left + right) / 2
        if data[mid] == k:
            return mid
        elif data[mid] > k:
            right = mid - 1
        else:
            left = mid + 1
    return -1

追問,如果給定的數組中中有多個重復值,如何進行查找?描述一下思路。當時理解成查找數組中這個值的始末索引了,回答的是使用二分法分別查找始末索引就可以了。面試官說直接使用二分法就可以。額?

5.經典問題,一次可以上1個台階,也可以上2個...n個,問一共有多少種上法

當時寫的代碼大概如下,並用公式表示了一下。

def fib(n):
    a, b = 1, 2
    for i in range(n):
        yield a
        a, b = b, 2 * b

6.當從b模塊中導入a,運行b,會輸出什么?a,b內容如下所示

# a.py
print 'm'


def f():
    print 'fm'


class A(object):
    print 'A.m'

    def fa(self):
        print 'A.f.m'

# b.py

import a

運行b后,輸入結果如下所示:

m

A.m

面試過程:我當時記得說了Python中的函數會延遲生成,在導入時不直接執行,而模塊的頂級代碼會直接執行。類變量沒說,理解不夠深入。

原因:Python模塊導入時,會創建一個module對象,並插入到sys.modules中,可以通過以下代碼查看模塊的屬性

print dir(sys.modules['a'])

模塊中的頂層變量會在模塊導入時就執行,類的類變量也是如此,因此在模塊中應該盡量避免這種,放在函數中進行延遲生成。這里需要深入了解模塊的導入機制

7.說一下對裝飾器的理解,原理是什么?如何使用裝飾器實現求函數的執行時間?

面試過程:裝飾器可以抽離出大量函數中與函數功能本身無關的雷同代碼並繼續重用,為已經存在的對象添加額外的功能,比如性能測試等。原理當時一下忘記了是閉包了,最后寫的求時間的裝飾器也不符合要求.

回顧總結:裝飾器原理是使用了閉包實現的,是一種面向切面編程的模式(對設計模式理解不多,下一步需要抽時間學習設計模式了!)。對裝飾器實現的執行時間,代碼如下所示:(Python中有自帶的timeit模塊用來求執行時間)。

import time
from functools import wraps


def timeit(func):
    @wraps(func)
    def wrapper():
        start = time.clock()
        func()
        end = time.clock()
        print 'used:', end - start

    return wrapper


@timeit
def f():
    time.sleep(3)

f()

8.對閉包的理解?

面試回答:我答的是在一個函數中返回的內部函數,在函數結束后,內部函數還可以繼續使用。(完全大白話!又一次尷尬了)

回顧總結:閉包(Closure)是詞法閉包(Lexical Closure)的簡稱,是引用了自由變量的函數。這個被引用的自由變量將和這個函數一同存在,即使已經離開了創造它的環境也不例外。

9.對函數對象的理解?

回顧總結:忘了咋回答的了!函數可以賦值給變量、可以作為元素添加到集合對象中、可作為參數值傳遞給其它函數,還可以當做函數的返回值。對於函數對象的理解,可以看這里

10.如何理解Python中一切皆對象?

回顧總結:Python中所有的對象都有身份、類型和值。具體內容可以直接搜索,感覺這個博客寫的也不錯。當然要最好的理解還是看源碼。

11.對協程的理解,協程和線程的區別?

回顧總結: 協程是使用裝飾器實現的,GIL,程序員自己來控制。協程適合I/O密集型操作,異步功能。

12.二叉樹求深度?

遞歸思路

def get_depth(tree):
    if not tree:
        return 0
    if not tree.left and not tree.right:
        return 1
    return 1 + max(get_depth(tree.left), get_depth(tree.right))

13.MySQL索引優化?

回顧總結:這個在很多面試中會問到,工作中也會用到,需要認真學好MySQL。關鍵點:最左匹配,聯合索引,在哪種情況下建立索引,B樹原理,explain查看語句等。網上搜一下挺多內容的,不過還是最好看一下《高性能MySQL》這本書。

14.Redis緩存,數據類型等?

回顧總結:字符串、列表、hash、set、有序集合等。

總結

面試內容相對比較深,廣度一般,關注了很多Python的深層原理。

反思

  1. 對於很多特性自己還是了解的不夠深入;
  2. 在學習過程中,自己習慣於把一些概念轉化成大白話來加深理解,導致對概念的專業術語反而記不住了,說起來顯得不專業;
  3. 代碼能力有待提高;
  4. 要想面試好,還是需要更好的准備的,工作之余直接去面試有點倉促。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM