Python企業面試題2 —— 基礎篇

生而自由爱而无畏發表於2024-04-05
1. re 的match和search區別?
re.match 嘗試從字串的起始位置匹配一個模式,如果不是起始位置匹配成功的話,match()就返回none。
re.search 掃描整個字串並返回第一個匹配成功的值。
2. 什麼是正則的貪婪匹配?
匹配一個字串沒有節制,能匹配多少就去匹配多少,直到沒有匹配的為止。
3. 求結果:
a. [i % 2 for i in range(10)]
print([i % 2 for i in range(10)])	# [0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
print([i for i in range(10)])	# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print([10 % 2])		# [0]
# % 是個運算子。
b. (i % 2 for i in range(10))
print((i % 2 for i in range(10)))
# <generator object <genexpr> at 0x00000233D5D45EB0> 生成器
# 在py中,有一種自定義迭代器的方式,稱為生成器(Generator)。
# 定義生成器的兩種方式:
# 1. 建立一個generator,只要把一個列表生成式的[]改成(),就建立了一個generator:generator儲存的是演算法,每次呼叫next(),就計算出下一個元素的值,直到計算到最後一個元素。沒有更多的元素時,丟擲StopIteration的錯誤。
# 2. 定義generator的另一種方法。如果一個函式定義中包含yield關鍵字,那麼這個函式就不再是一個普通的函式,而是一個generator。
4. 求結果
a. 1 or 2	# 1
b. 1 and 2	# 2
c. 1 < (2 == 2)		# False
d. 1 < 2 == 2	# True
5. 如何實現 "1,2,3" 變成 ['1', '2', '3'], 反過來呢?
list("1, 2, 3".split(','))
[int(x) for x in ['1', '2', '3']]
6. 一行程式碼實現刪除列表中重複的值?
list(set([1, 2, 3, 4, 1, 2, 5, 6, 4]))
7. 如何在函式中設定一個全域性變數?

py中的global語句是被用來宣告全域性變數的。

x = 2
def func():
	global x
	x = 1
	return x
func()
print(x)	# 1
8. logging 模組的作用以及應用場景?
logging 模組定義的函式和類為應用程式和庫的開發實現了一個靈活的事件日誌系統。
作用:可以瞭解程式執行情況,是否正常,在程式的出現故障快速定位出錯地方及故障分析。
9. 請用程式碼簡答實現 stack?
  • Stack() 建立一個新的空棧
  • push(item) 新增一個新的元素item到棧頂
  • pop() 彈出棧頂元素
  • peek() 返回棧頂元素
  • is_empty() 判斷棧是否為空
  • size() 返回棧的元素個數
# 實現一個棧stack,後進先出
class Stack:
    def __init__(self):
        self.items = []

    def is_empty(self):
        # 判斷是否為空
        return self.items == []

    def push(self, item):
        # 加入元素
        self.items.append(item)

    def pop(self):
        # 彈出元素
        return self.items.pop()

    def peek(self):
        # 返回棧頂元素
        return self.items[len(self.items) - 1]

    def size(self):
        # 返回棧的大小
        return len(self.items)

if __name__ == '__main__':
    stack = Stack()
    stack.push("H")
    stack.push("E")
    stack.push("L")
    print(stack.size())     # 3
    print(stack.peek())     # L
    print(stack.pop())      # L
    print(stack.pop())      # E
    print(stack.pop())      # H
10. 常用字串格式化有哪幾種?
  • 佔位符 %
    %d 表示那個位置是整數;%f 表示浮點數;%s表示字串。
print('Hello, %s' % 'Python')   # Hello, Python
print('Hello, %d %s %2f' % (666, 'Python', 9.99))
#   Hello, 666 Python 9.990000
  • format
print('{k} is {v}'.format(k = 'python', v = 'easy'))    # python is easy
print('{0} is {1}'.format('python', 'easy'))    # python is easy
11. 簡述生成器、迭代器、可迭代物件、裝飾器?
  1. 生成器:
    包括含有yield關鍵字,生成器也是迭代器,調動next把函式變成迭代器。

  2. 迭代器:
    含有 __iter____next__方法(包含__iter__方法的可迭代物件就是迭代器)

  3. 可迭代物件:
    一個類內部實現__iter__方法且返回一個迭代器。

  4. 裝飾器:
    能夠在不修改原函式程式碼的基礎上,在執行前後進行定製操作,閉包函式的一種應用。
    場景:

  • flask 路由系統
  • flask before_request
  • csrf
  • django 內建認證
  • django 快取
import functools

def wrapper(func):
    @functools.wraps(func)      # 不改變原函式屬性
    def inner(*args, **kwargs):
        # 執行函式前
        return func(*args, **kwargs)
        # 執行函式後
    return inner
# 1. 執行wrapper函式,並將被裝飾的函式當做引數。  wrapper(index)
# 2. 將第一步的返回值,重新賦值給新index = wrapper(老index)
@wrapper    # index=wrapper(index)
def index(x):
    return x+100

呼叫裝飾器其實是一個閉包函式,為其他函式新增附加功能,不修改被修改的原始碼和不修改被修飾的方式,裝飾器的返回值也是一個函式物件。
比如:插入日誌、效能測試、事物處理、快取、許可權驗證等,有了裝飾器,就可以抽出大量與函式功能本身無關的雷同程式碼並繼續重用。

12. def func(a, b=[]) 這種寫法有什麼坑?
def func(a, b=[]):
    b.append(1)
    print(a, b)

func(a=2)   # 2 [1]
func(2)     # 2 [1, 1]
func(2)     # 2 [1, 1, 1]
想每次執行只輸出[1],預設引數應該設定為None
13. 列舉常見的內建函式
  • abs() 返回數字的絕對值
  • map() 根據函式對指定序列做對映
    map() 函式接受兩個引數,一個是函式,一個是可迭代物件,map將傳入的函式依次作用到序列的每個元素,並把結果作為新的list返回。

返回值:
py2:返回列表
py3:返回迭代器

例子1:

def mul(x):
    return x*x
n = [1, 2, 3, 4, 5]
res = list(map(mul, n))
print(res)  # [1, 4, 9, 16, 25]

例子2:

ret = map(abs, [-1, -5, 6, -7])
print(list(ret))    # [1, 5, 6, 7]
  • filter
    filter()函式接收一個函式 f(函式)和一個list(可迭代物件),這個函式 f的作用是對每個元素進行判斷,返回True或False,filter()根據判斷結果自動過濾掉不符合條件的元素,返回由符合條件元素組成的新list。
def is_odd(x):
    return x % 2 == 1
v = list(filter(is_odd, [1, 4, 6, 7, 9, 12, 17]))
print(v)    # [1, 7, 9, 17]

map 與 filter 總結

引數:都是一個函式名 + 可迭代物件
返回值:都是返回可迭代物件
區別:filter是做篩選的,結果還是原來就在可迭代物件中的項。map是對可迭代物件中每一項做操作的,結果不一定是原來就在可迭代物件中的項
  • isinstance/type
    isinstance()函式來判斷一個物件是否是一個已知的型別,類似type()。
    isinstance() 與 type() 區別:
    type() 不會認為子類是一種父類型別,不考慮繼承關係。
    isinstance() 會認為子類型別是一種父類型別,考慮繼承關係。
    如果要判斷兩個型別是否相同推薦使用 isinstance()。
a = 2
print(isinstance(a, int))   # True
print(isinstance(a, str))   # False
class A:
    pass
class B(A):
    pass
print("isinstance", isinstance(A(), A))     # isinstance True
print("type",type(A()) == A)     # type True
print("isinstance", isinstance(B(), A))     # isinstance True
print("type",type(B()) == A)     # type False
  • 拉鍊函式
    zip 拉鍊函式,將物件中對應的元素打包成一個個元組,然後返回由這些元組組成的列表迭代器。如果各個迭代器的元素個數不一致,則返回列表長度與最短的物件相同。
print(list(zip([0, 1, 3], [5, 6, 7], ['a', 'b'])))  # [(0, 5, 'a'), (1, 6, 'b')]

zip() 函式用於將可迭代物件作為引數,將物件中對應的元素打包成一個個元組,然後返回由這些元組組成的列表。

>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> c = [4, 5, 6, 7, 8]
>>> zipped = zip(a, b)	# 打包為元組的列表 [(1, 4), (2, 5), (3, 6)]
>>> zip(a, c)	# 元素個數與最短的列表一致 [(1, 4), (2, 5), (3, 6)]
>>> zip(*zipped)	# 與zip相反,可理解為解壓,返回二維矩陣式	[(1, 2, 3), (4, 5, 6)]
  • reduce
    reduce() 函式會對引數序列中元素進行累積。函式將一個資料集合(連結串列、元組等)中的所有資料進行下列操作
    注意:py3已經將reduce()函式從全域性名字空間裡移除了,它現在被放置在functools模組裡,如果想要使用它,則需要用過引用引入functools模組來呼叫reduce()函式。
from functools import reduce
def add(x, y):
    return x + y
print(reduce(add, [1, 2, 3, 4, 5]))     # 15
print(reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]))    # 15
print(reduce(add, range(1, 101)))   # 5050
14. filter、map、reduce 的作用?

內建函式:map、reduce、filter 的用法和區別

  • map:根據函式對指定序列做對映
map
引數:接收兩個引數一個是函式,一個是序列(可迭代物件)
返回值:py2返回列表,py3返回迭代器
例子:
abs() 函式返回數字的絕對值
新的內容的個數等於原內容的個數
ret = map(abs, [-1, -5, 6, -7])
print(list(ret))	# [1, 5, 6, 7]
  • filter:過濾函式 新的內容少於等於原內容的時候。才能使用filter,filter()函式用於過濾序列,過濾不符合條件的元素,返回由符合條件元素組成的新列表。

引數:
function 函式
iterable 可迭代物件

返回值:返回列表

# 篩選大於 10 的數
def is_odd(x):
    if x > 10:
        return True
ret = filter(is_odd, [1, 4, 5, 7, 8, 9, 76])    # 為迭代器
print(list(ret))    # 76
  • reduce:對於序列內所有元素進行累計操作
    reduce() 函式會對引數序列中元素進行累積,函式將一個資料集合(連結串列、元組等)中的所有資料進行下列操作。
from functools import reduce
def add(x, y):
    return x + y
print(reduce(add, [1, 2, 3, 4, 5]))     # 15
print(reduce(lambda x, y: x + y, [1, 2, 3, 4, 5]))  # 15
print(reduce(add, range(1, 101)))   # 5050
15. 用py實現一個二分查詢的函式?

二分查詢演算法:簡單地說,就是將一個列表先排序好,比如按照從小到大的順序排列,當給定一個資料,比如3,查詢3在列表中的位置時,可以先找到列表中間的數li[middle]和3進行比較,當它比3小時,那麼3一定是在列表的右邊,反之則3在列表的左邊。比如它比3小,則下次就可以只比較[middle+1, end]的數,繼續使用二分法,將它一分為二,直到找到3這個數返回或者列表全部遍歷完成(3不在列表中)
優點:效率高,時間複雜度為O(logN);
缺點:資料要是有序的,順序儲存。

li = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def search(someone, li):
    l = -1
    h = len(li)
    while l + 1 != h:
        m = int((l + h) / 2)
        if li[m] < someone:
            l = m
        else:
            h = m
    p = h
    if p >= len(li) or li[p] != someone:
        print("元素不存在")
    else:
        str = "元素索引為%d" % p
        print(str)
search(3, li)   # 元素索引為2
16. 談談你對閉包的理解?
def foo():
    m = 3
    n = 5
    def bar():
        a = 4
        return m+n+a
    return bar
bar = foo()
print(bar())   # 12

說明:bar在foo函式的程式碼塊中定義。我們稱bar是foo的內部函式。在bar的區域性作用域中可以直接訪問foo區域性作用域中定義的m、n變數。簡單地說,這種內部函式可以使用外部函式變數的行為,就叫閉包。
閉包的意義與應用

17. 如何生成一個隨機數?
import random
# 生成一個0-1的隨機浮點數:0 <= n < 1.0
print(random.random())
# 生成一個指定範圍內的整數
print(random.randint(1, 10))
18. 如何使用py刪除一個檔案?
import os
file = r'E:/test.txt'
if os.path.exists(file):
    os.remove(file)
    print('delete success')
else:
    print('no such file: %s' % file)
19. 談談你對物件導向的理解(三大特性及解釋)?

物件導向是一種程式設計思想,以類的眼光來看待事物的一種方式。將共有的屬性和方法的事物封裝到同一個類下面。
封裝:將共同的屬性和方法封裝到同一個類下面

  • 第一層面:建立類和物件會分別建立二者的名稱空間,我們只能用類名. 或者obj. 的方式去訪問裡面的名字,這本身就是一種封裝
  • 第二層面:類中把某些屬性和方法隱藏起來(或者說定義成私有的),只在類的內部使用、外部無法訪問,或者留下少量介面(函式)供外部訪問。

繼承:將多個類的共同屬性和方法封裝到一個父類下面,然後再用這些類來繼承這個類的屬性和方法

多型:python天生是支援多型的。指的是基類的同一個方法在不同的派生類中有著不同的功能。

20.物件導向中深度優先和廣度優先是什麼?

Python的類可以繼承多個類,如果繼承了多個類,那麼其尋找方法的方式有兩種:
當類是經典類時,多繼承情況下,會按照深度優先方式查詢。 py3
當類是新式類時,多繼承情況下,會按照廣度優先方式查詢。 py2
簡單點說就是:經典類是縱向查詢,新式類是橫向查詢。
經典類和新式類的區別就是,在宣告類的時候,新式類需要加上object關鍵字。在py3中預設全是新式類。

相關文章