python開發 面試題

1、簡述列表與元組的區別
答:
元組tuple與列表List相同點
元組tuple與列表List都是序列類型的容器對象,能夠存聽任何類型的數據、支持切片、迭代等操做。

元組tuple與列表List區別:
1.不可變與可變:兩種類型除了字面上的區別(括號與方括號)以外,最重要的一點是tuple是不可變類型,大小固定,而list是可變類型、數據能夠動態變化,這種差別使得二者提供的方法、應用場景、性能上都有很大的區別。
2.一樣大小的數據,tuple 佔用的內存空間更少,原子性的 tuple 對象還可做爲字典的鍵。
3.同構與異構:tuple用於存儲異構(heterogeneous)數據,當作沒有字段名的記錄來用,好比用tuple來記錄一我的的身高、體重、年齡。而列表通常用於存儲同構數據(homogenous),同構數據就是具備相贊成義的數據

總結:元組和列表是經常使用的數組類型,在使用過程當中,列表擅長對可變數據的操做,通常用於同構數據,而元組主要用於異構數據,數據庫操做中查詢出來的記錄就是由元組構成的列表結構。



2、簡述核心數據類型列列表中 append() | extend() | insert()方法的功能與區別
append():在列表尾部追加元素
extend():在列表尾部迭代追加元素
insert():在列表指定索引位置插入元素


3、用盡量多的方法描述如何規避在對字典進行key索引取值時引起 KeyError錯誤
方式一:
dic = {'name': 'alex', 'age': 46, 'sex': 'laddyboy'}
ret = dic.get('name1')  #None
方式二:
dic = {'name': 'alex', 'age': 46, 'sex': 'laddyboy'}
for key in dic:
    print(key,dic[key])
方式三:
dic = {'name': 'alex', 'age': 46, 'sex': 'laddyboy'}
if 'name' in dic:
    print(dic['name'])



4、什麼是線程? 什麼是進程? 什麼是協程? 在Python中多線程適用於什麼場景?爲何?

進程:
進程(Process)是計算機中的程序關於某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位,是操做系統結構的基礎。在早期面向進程設計的計算機結構中,進程是程序的基本執行實體;在當代面向線程設計的計算機結構中,進程是線程的容器。程序是指令、數據及其組織形式的描述,進程是程序的實體。
狹義定義:進程是正在運行的程序的實例(an instance of a computer program that is being executed)。
廣義定義:進程是一個具備必定獨立功能的程序關於某個數據集合的一次運行活動。它是操做系統動態執行的基本單元,在傳統的操做系統中,進程既是基本的分配單元,也是基本的執行單元。

線程:
線程(英語:thread)是操做系統可以進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運做單位。一條線程指的是進程中一個單一順序的控制流,一個進程中能夠併發多個線程,每條線程並行執行不一樣的任務。在Unix System V及SunOS中也被稱爲輕量進程(lightweight processes),但輕量進程更多指內核線程(kernel thread),而把用戶線程(user thread)稱爲線程。

協程:
協程:是單線程下的併發,又稱微線程,纖程。英文名Coroutine。一句話說明什麼是線程:協程是一種用戶態的輕量級線程,即協程是由用戶程序本身控制調度的。


應用場景:
多進程適合在CPU 密集型操做(cpu 操做指令比較多,如科學計算,位數多的浮點運算)
多線程適合在IO 密集型操做(讀寫數據操做較多的,好比爬蟲)
 
why?
線程是併發 ,進程是並行
進程之間互相獨立, 是系統分配資源的最小單位 同一個進程中的全部線程共享資源

並行 : 同一時刻多個任務同時在運行
併發: 在同一時間間隔內 多個任務都在運行,可是並不會在同一時刻同時運行,存在交替執行的狀況

系統運行時,大部分的情況是cpu在等I/O(硬盤/內存)的讀/寫,這樣一來線程能夠來回切換 IO密集型操做使用併發更好。
cpu 密集型: 大部分時間用來作計算 邏輯判斷等 cpu 動做的程序稱之cpu 密集型





5、介紹一下二分查找算法 並用Python代碼來實現它

二分查找也稱折半查找(Binary Search),它是一種效率較高的查找方法。可是,折半查找要求線性表必須採用順序存儲結構,並且表中元素按關鍵字有序排列
例子:
l = [2, 3, 5, 10, 15, 16, 18, 22, 26, 30, 32, 35, 41, 42, 43, 55, 56, 66, 67, 69, 72, 76, 82, 83, 88]
def func(l, aim,count):
    mid = (len(l) - 1) // 2

    if l:
        if aim > l[mid]:
            count += 1
            func(l[mid + 1:], aim, count)
        elif aim < l[mid]:
            count += 1
            func(l[:mid], aim,count)
        elif aim == l[mid]:
            count += 1
            print("找了%d次,才找到%d"%(count,aim))
    else:
        print('找不到')

func(l,66,0)#找了5次,才找到66





6、什麼是裝飾器,它的應用場景是什麼? 請寫出經過裝飾器裝飾一個帶參數的函數的代碼

裝飾器:
其實裝飾器本質是閉包,在不改變原函數的調用指令狀況下,給原函數增長額外的功能。它的傳參,返回值都是藉助內層函數inner,它之因此藉助內層函數inner就是爲了讓被裝飾函數在裝飾器裝飾先後,沒有任何區別,看起來沒有變化。

應用場景是:
1. 受權(Authorization)
2. 日誌(Logging)
3,函數執行時間統計
4,執行函數前預備處理
5,執行函數後清理功能
等等。。。

def wrapper(f):
    def inner(*args,**kwargs):
        ret =f(*args,**kwargs)
        return ret
    return inner

@wrapper  # func = wrapper(func) = inner
def func(a,b):
    print(a,b)
    sum = a + b
    return sum

ret = func(3,4) # inner(3,4)
print(ret)





7、簡述什麼是深拷貝? 什麼是淺拷貝並說出以下代碼得出的結果是什麼?

直接賦值:其實就是對象的引用(別名)。
淺拷貝(copy):拷貝父對象,不會拷貝對象的內部的子對象。
深拷貝(deepcopy): copy 模塊的 deepcopy 方法,徹底拷貝了父對象及其子對象。

x = ['lily', '20', 'hr']
y = x
x[0] = 'lucy'
z = list(x)
x[0] = ‘lilei’
請問變量 y 的結果和 z的結果分別是什麼
y的結果:['lilei', '20', 'hr'] #賦值
z的結果:['lucy', '20', 'hr']  #淺拷貝

x = ['lily', 20, ['study', 'coding']]
y = x[:]
import copy
z = copy.deepcopy(x)
x[2][0] = 'lol'
請問此時變量 y 和 z 的值分別是什麼? 爲何?
y的結果:['lily', 20, ['lol', 'coding']]  #why  淺拷貝
z的結果:['lily', 20, ['study', 'coding']]   #why 深拷貝





8、儘量多的寫出你掌握的建立字典的方式
方式一:經過關鍵字dict和關鍵字參數建立
a = dict(name='alex',age='18')
print(a)

方式二:直接賦值建立
a = {'name':'alex','age':18}
print(a,type(a))

方式三:經過二元組列表建立
li = [('name', 'alex'), ('age', 18)]
dic = dict(li)
print(dic,type(dic))

方式四:經過字典推導式建立
dic = {i:2*i for i in range(3)}
print(dic,type(dic))

方式五:dict和zip結合建立
dic = dict(zip('abc', [1, 2, 3]))
print(dic,type(dic))

方式六:經過dict.fromkeys()建立,一般用來初始化字典, 設置value的默認值
dic = dict.fromkeys(range(3), 'x')
print(dic,type(dic))



9、有列表 a =[‘apple’, ‘banana’, ‘orange’] 現須要將其中各元素經過」|」拼接起來,請寫出你的實現方式,並說明爲什什麼你要這樣實現
a =['apple', 'banana', 'orange']
b = '|'.join(a)
print(b)
why?可使用字符串方法join()進行拼接列表元素





10、根據類的命名空間相關知識 說出下面代碼會得出什什麼結果
class c1:
    var1 = 'apple'
    def __init__(self):
        self.var2 = 10
x = c1()
y = c1()
x.var1 = 100

# 此時下面兩句句print會打印出什什麼內容
print(x.var1, x.var2) #100,10
print(y.var1, y.var2) #apple,10

why:
    類實例化對象時,會建立類的實例化對象空間。 x.var1 = 100 至關於實例對象x 新開闢了一個變量空間var1  優先查找本身的名稱空間 全部打印100,10
    y.var1 是 apple 是由於本身的實例空間沒有找到var1變量就去類的名稱空間查找 




11、請簡述 __new____init__ 的區別
1 __new__方法得到空間地址(實例對象建立第一步必須建立空間)
2 將空間地址做爲第一個位置參數傳給__init__ ,完成實例空間賦值屬性的過程   self變量等於addr變量  存儲地址空間指針




12、 在Python中 子類如何重寫父類的構造函數
class A(object):

    def __new__(cls, *args, **kwargs):  # c了基類object的__new__方法
        print("this is 構造方法")
        addr = super().__new__(cls)  # 必須調用父類開闢空間的方法(操做底層硬件) 默認傳參 cls(當前類名)
        print("addr", addr)
        return addr

    def __init__(self, *args, **kwargs):  # 覆蓋了基類object的__init__方法
        print("self", self)
        print("this is 初始化方法")
A()
# this is 構造方法
# addr <__main__.A object at 0x0000026B36E65EF0>
# self <__main__.A object at 0x0000026B36E65EF0>
# this is 初始化方法



十3、請簡述Python中的實例方法 靜態方法 類方法
實例方法
    定義:第一個參數必須是實例對象,該參數名通常約定爲「self」,經過它來傳遞實例的屬性和方法(也能夠傳類的屬性和方法);
    調用:只能由實例對象調用。

類方法
    定義:使用裝飾器@classmethod。第一個參數必須是當前類對象,該參數名通常約定爲「cls」,經過它來傳遞類的屬性和方法(不能傳實例的屬性和方法);
    調用:實例對象和類對象均可以調用。

靜態方法
    定義:使用裝飾器@staticmethod。參數隨意,沒有「self」和「cls」參數,可是方法體中不能使用類或實例的任何屬性和方法;
    調用:實例對象和類對象均可以調用。




十4、多態 封裝 繼承 是OOP的三大基石, 請簡述封裝的意義是什麼? 並用Python來實現
封裝:隱藏對象的屬性和實現細節,僅對外提供公共訪問方式。
1. 將變化隔離; 
2. 便於使用;
3. 提升複用性; 
4. 提升安全性;

class A:
    __N=0 #類的數據屬性就應該是共享的,可是語法上是能夠把類的數據屬性設置成私有的如__N,會變形爲_A__N
    def __init__(self):
        self.__X=10 #變形爲self._A__X
    def __foo(self): #變形爲_A__foo
        print('from A')
    def bar(self):
        self.__foo() #只有在類內部才能夠經過__foo的形式訪問到.

a = A()
a.bar() #from A




十5、簡述Python代碼異常處理理中 raise 與 assert語句的做用, 默認狀況下, try與assert只能觸發內置異常如(TypeError,KeyError),現須要實現引起用戶自定義異常(badString),請寫出代碼

raise的做用:python能夠自動觸發異常,raise(內置函數)的定義爲顯示的拋出異常,用戶可使用raise進行判斷,顯式的引起異常,raise執行後程序將再也不向下執行。
assert的做用:在本身不肯定、或者懷疑會出錯的時候用斷言,或者在DEBUG時候用斷言


class EvaException(BaseException):
    def __init__(self,msg):
        self.msg=msg
    def __str__(self):
        return self.msg

user = input("請輸入用戶名:")
pwd = input("請輸入密碼:")
if user == 'alex':
    try:
        raise EvaException('用戶名已存在!')
    except EvaException as e:
        print(e)

if len(pwd) < 6:
    try:
        raise EvaException('密碼不能低於6位數!')
    except EvaException as e:
        print(e)


        
十六:如何實現Python多進程之間的數據共享?
使用數據庫來解決如今進程之間的數據共享問題
用Manager實現數據共享
from multiprocessing import Manager,Process,Lock
def work(d,lock):
    with lock: #不加鎖而操做共享的數據,確定會出現數據錯亂
        d['count']-=1

if __name__ == '__main__':
    lock=Lock()
    with Manager() as m:
        dic=m.dict({'count':100})
        p_l=[]
        for i in range(100):
            p=Process(target=work,args=(dic,lock))
            p_l.append(p)
            p.start()
        for p in p_l:
            p.join()
        print(dic)




十7、簡述內置函數 map() | zip() | filter() | reduce() 的功能

zip:函數用於將可迭代的對象做爲參數,將對象中對應的元素打包成一個個元組,而後返回由這些元組組成的列表。若是各個迭代器的元素個數不一致,則返回列表長度與最短的對象相同。
filter 過濾 經過你的函數,過濾一個可迭代對象
map:會根據提供的函數對指定序列作映射。
reduce() 函數會對參數序列中元素進行累積。



十9、經過列表解析與三元表達式處理列表 [1,2,3,4,5], 對其中小於3的元素加2 對大於等於3的元素加3
print([i+2 for i in [1,2,3,4,5] if i < 3] + [ i+3 for i in [1,2,3,4,5] if i >= 3])


二10、簡述Python中正則表達式的貪婪模式與非貪婪模式
貪婪與非貪婪模式影響的是被量詞修飾的子表達式的匹配行爲,
貪婪模式在整個表達式匹配成功的前提下,儘量多的匹配,
而非貪婪模式在整個表達式匹配成功的前提下,儘量少的匹配。非貪婪模式只被部分NFA引擎所支持。 
面試題一 20190621
相關文章
相關標籤/搜索