Python面試題總結

您能夠關注公衆號《Python數據結構》瞭解更多知識。

i = i+1 和 i += 1

  • 對於不可變數據類型(str、int、tuple)
因爲自己是不可變數據類型,執行後都會生產新的對象
x = 1
print(id(x))  # 1510566928
x += 1
print(id(x))  # 1510566960
---------------------------
x = 1
print(id(x))  # 1510566954
x = x + 1
print(id(x)) # # 1510566998
  • 可變數據類型狀況(list、dict)
能夠看到 使用 += 並不會改變對象的內存地址
x = [1, 2]
print(id(x))  # 2701823038387
x = x + [3, 4]
print(id(x))  # 2701823038334
------------------
x = [1, 2]
print(id(x))  # 2701823038344
x += [3, 4]
print(id(x))  # 2701823038344
  • 注意
n = n + n 做用域問題內部爲[1, 2, 1, 2], 外部仍爲[1, 2]
def num(n):
    n = n + n
x = [1, 2]
num(x)
print(x)  # [1, 2]
--------------------
def num(n):
    n += n
x = [1, 2]
num(x)
print(x)  # [1, 2, 1, 2]

內建函數

zip

key = [key for key in dict(zip(('a','b','c','d','e'),(1,2,3,4,5))) ]
print(key)
--------------------------------------------------------
['a', 'b', 'c', 'd', 'e']
A0 = dict(zip(('a','b','c','d','e'),(1,2,3,4,5)))
A1 = range(10)
A2 = [i for i in A1 if i in A0]
A3 = [A0[s] for s in A0]
A4 = [i for i in A1 if i in A3]
A5 = {i:i*i for i in A1}
A6 = [[i,i*i] for i in A1]
-------------------------------------------------------------
A0 = {'a': 1, 'c': 3, 'b': 2, 'e': 5, 'd': 4}
A1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
A2 = []
A3 = [1, 3, 2, 5, 4]
A4 = [1, 2, 3, 4, 5]
A5 = {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
A6 = [[0, 0], [1, 1], [2, 4], [3, 9], [4, 16], [5, 25], [6, 36], [7, 49], [8, 64], [9, 81]]

閉包

做用——保存局部信息不被銷燬。
def num2(n):
    i = 1
    def num_in():
        nonlocal i
        i = i + n
        print(i)
    return num_in

i = 0
start = num2(3)
while i<5:
    start()
    i += 1

匿名函數(lambda)

與正常寫法相比,使用匿名函數至關簡潔
  • map() 遍歷全部
a = [1, 2, 3]
x = []
for each in a:
    x.append(each+1)

print(x)
### 使用map(func, iterable)
print(list(map(lambda x: x+1, a)))
  • reduce(func, seq) 積累每次計算的值
def num(x, y):
    return x + y
print(reduce(num, [1, 2, 3, 4]))
--------------------------
print(reduce(lambda x, y: x*y, [1, 2, 3, 4]))
  • filter(func, iterable) 過濾知足條件的值
print(list(filter(lambda x: x%2==0,range(10))))

進程和線程的區別

  • 進程是資源(CPU、內存等)分配的基本單位,它是程序執行時的一個實例。
  • 線程是程序執行時的最小單位,它是進程的一個執行流。
  • 進程有本身的獨立地址空間,每啓動一個進程,系統就會爲它分配地址空間,創建數據表來維護代碼段、堆棧段和數據段,這種操做很是昂貴
  • 線程是共享進程中的數據的,使用相同的地址空間,所以CPU切換一個線程的花費遠比進程要小不少,同時建立一個線程的開銷也比進程要小不少
  • 進程實現
from multiprocessing import Pool
import time
import random
import os


def work(msg):
    start = time.time()
    print("work{}開始執行,id爲{}".format(msg, os.getpid()))
    time.sleep(random.random()*2)
    stop = time.time()
    print("work{}耗時{}.".format(msg, stop-start))

p = Pool()
for i in range(10):
    # 非堵塞運行
    p.apply_async(work, args=(i,))
    # 堵塞進行
    # p.apply(work, args=(i,))


print("開始")
p.close()
p.join()
print("結束")
  • 線程實現
import threading
import os
from time import sleep

def sorry(i):
    print('say sorry  {}'.format(i))
    sleep(1)

if __name__ == '__main__':
    for i in range(1,10):
        t = threading.Thread(target=sorry, args=(i,))
        t.start()

協程

協程以前咱們明白Python的進程和線程,這裏咱們來講一下協程
  • 子程序切換不是線程切換,而是由程序自身控制
  • 沒有線程切換的開銷,和多線程比,線程數量越多,協程的性能優點就越明顯
  • 不須要多線程的鎖機制,由於只有一個線程,也不存在同時寫變量衝突,在協程中控制共享資源不加鎖
  • 協程實現
def custumer():
    r = ''
    while True:
        n = yield r  # 接受send的值  返出yield的值
        if not n:
            return
        print('custer {}'.format(n))
        r = 'done'

def produce(c):
    c.send(None)  # 啓動
    n = 0
    while n < 5:
        n += 1
        print('custer {}'.format(n))
        r = c.send(n)
        print('custer return {}'.format(r))
    c.close()

c = custumer()
produce(c)

GIL

Python並不支持真正意義上的多線程。Python中提供了多線程包,可是若是你想經過多線程提升代碼的速度,使用多線程包並非個好主意。Python中有一個被稱爲Global Interpreter Lock(GIL)的東西,它會確保任什麼時候候你的多個線程中,只有一個被執行。線程的執行速度很是之快,會讓你誤覺得線程是並行執行的,可是實際上都是輪流執行。通過GIL這一道關卡處理,會增長執行的開銷。這意味着,若是你想提升代碼的運行速度,使用threading包並非一個很好的方法。
不過仍是有不少理由促使咱們使用threading包的。若是你想同時執行一些任務,並且不考慮效率問題,那麼使用這個包是徹底沒問題的,並且也很方便。可是大部分狀況下,並非這麼一回事,你會但願把多線程的部分外包給操做系統完成(經過開啓多個進程),或者是某些調用你的Python代碼的外部程序(例如Spark或Hadoop),又或者是你的Python代碼調用的其餘代碼(例如,你能夠在Python中調用C函數,用於處理開銷較大的多線程工做)。

copy

Python拷貝分爲深拷貝和淺拷貝
  • 淺拷貝對子對象不拷貝,深拷貝所有拷貝
l1 = [1, 2, [3, 4]]
l2 = copy.copy(l1)
l1.append(5)
l1[2].append(5)  # 子對象 改變
print(l1)
print(l2)
--------------
[1, 2, [3, 4, 5], 5]
[1, 2, [3, 4, 5]]
  • 深拷貝完是兩個徹底不相干的對象
l1 = [1, 2, [3, 4]]
l2 = copy.deepcopy(l1)
l1.append(5)
l1[2].append(5)
print(l1)
print(l2)
--------------
[1, 2, [3, 4, 5], 5]
[1, 2, [3, 4]]

垃圾回收機制

  • 引用計數
import sys
# 請在Python解釋器下運行  爲 2  建立一次 調用一次
str1 = 'hello world'
print(sys.getrefcount(str1))
  • 分代技術
Python默認定義了三代對象集合,索引數越大,對象存活時間越長
Python中使用了某些啓發式算法(heuristics)來加速垃圾回收。例如,越晚建立的對象更有可能被回收。對象被建立以後,垃圾回收器會分配它們所屬的代(generation)。每一個對象都會被分配一個代,而被分配更年輕代的對象是優先被處理的。
  • 引用循環
垃圾回收器會定時尋找這個循環,並將其回收。舉個例子,假設有兩個對象o1和o2,並且符合o1.x == o2和o2.x == o1這兩個條件。若是o1和o2沒有其餘代碼引用,那麼它們就不該該繼續存在。但它們的引用計數都是1。

is和==

# is 比較的是內存地址   == 比較內容和數據類型
a = [1, 2, 3]
b = a
print(a is b)
print(a == b)

c = copy.deepcopy(a)
print(a is c)
print(a == c)
-------------
True
True
False
True

文件操做

read,readline和readlines

read 讀取整個文件
readline 讀取下一行,使用生成器方法
readlines 讀取整個文件到一個迭代器以供咱們遍歷

遞歸輸出文件

import os

def print_directory_contents(sPath):
    for sChild in os.listdir(sPath):
        sChildPath = os.path.join(sPath, sChild)
        if os.path.isdir(sChildPath):
            print_directory_contents(sChildPath)
        else:
            print(sChildPath)
print_directory_contents('F:\\GZ\\mxgController')

Fibonacci數列

def fab(n):
    a, b = 0, 1
    while n:
        yield b
        a, b = b, a+b
        n -= 1

內存管理

  • 小整數緩存池
a = 1
b = 1
print(a is b) # True
  • 短字符串
# True
a = "good"
b = "good"
print(a is b)

# False
a = "very good morning"
b = "very good morning"
print(a is b)

# False
a = []
b = []
print(a is b)

函數調用

函數賦值會開闢新空間,即[] 和 [3, 2, 1]內存地址不同,前者引用,後者覆蓋
def f(x, l=[]):
    for i in range(x):
        l.append(i*i)
    print(l)

f(2) # [0, 1]
f(3,[3,2,1]) # [3, 2, 1, 0, 1, 4]  # 本身單獨開闢
f(3) # [0, 1, 0, 1, 4]  # 和f(2)共用

三目

if/else

# 若果 a>b 成立  就輸出  a-b  不然 a+b
h = a-b if a>b else a+b

and/or

### and 全部值都爲真,返回最後一個真;如有一個假,返回第一個假
print(2 and 1 and 3)  # 3
print(1 and 3 and 0 and 4) # 0
print(1 and  0 and 3/0) # 0
### or  全部值都爲假,返回最後一個假;如有一個真,返回第一個真
print(0 or 1 or 1/0)
print(0 or '')
### 若是 a<b 返回True 不然返回a+b
print((a-b) and (a<b) or (a+b))

設計模式

單例---類方法方式

class Single():
    def __init__(self, name):
        self.name = name
    @classmethod
    def instance(cls, *args, **kwargs):
        if not hasattr(Single, "_instance"):
            Single._instance = Single(*args, **kwargs)
        return Single._instance
s1 = Single.instance('Gage')
s2 = Single.instance()
print(s1)
print(s2)

單例---new方式

class Single(object):
    __isstance = None
    __first_init = False
    def __new__(cls, *args, **kwargs):
        if not cls.__isstance:
            cls.__isstance = object.__new__(cls)
        return cls.__isstance
    def __init__(self, name):
        if not self.__first_init:
            self.name = name
            Singleton.__first_init = True
a = Single('a')
b = Single('b')
print(id(a))
print(id(b))

工廠模式

# 首先定義一個抽象基類
class CarStore(object):

    # 定義生產汽車的方法
    def createcar(self, name):
        pass

    # 根據類型去生產車
    def order(self, name):
        self.car = self.createcar(name)
        self.car.move()


# 定義4s店  實現抽象類
class AoDiCarStore(CarStore):

    def createcar(self, name):
        self.factory = CarFactory()
        return self.factory.createcar(name)


# 建立一個車
class AoDi():
    def move(self):
        print('移動')
# 定義一個工廠
class CarFactory():
    def createcar(self, name):
        self.name = name
        if self.name == 'AoDi':
            self.car = AoDi()
        return self.car
aodi = AoDiCarStore()
aodi.order('AoDi')

數據結構

鏈表成對調換

class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

class Solution:
    # @param a ListNode
    # @return a ListNode
    def swapPairs(self, head):
        if head != None and head.next != None:
            next = head.next
            head.next = self.swapPairs(next.next)
            next.next = head
            return next
        return head

單鏈表反轉

class Node(object):
    def __init__(self, data=None, next=None):
        self.data = data
        self.next = next

link = Node(1, Node(2, Node(3, Node(4, Node(5, Node(6, Node(7, Node(8, Node(9)))))))))

def rev(link):
    pre = link
    cur = link.next
    pre.next = None
    while cur:
        tmp = cur.next
        cur.next = pre
        pre = cur
        cur = tmp
    return pre

root = rev(link)
while root:
    print root.data
    root = root.next

快速排序

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])

二分搜索

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

掃碼關注《Python數據結構》

相關文章
相關標籤/搜索