python面試題——基礎篇(80題)


1、為什么學習Python?

Python是一門優秀的綜合語言, Python的宗旨是簡明、優雅、強大,
在人工智能、雲計算、金融分析、大數據開發、WEB開發、自動化運維、測試等方向應用廣泛

2、通過什么途徑學習的Python?

通過自學(博客、視頻、github等)

3、Python和Java、PHP、C、C#、C++等其他語言的對比?

Python:輕量級、易學、自由/開放源碼軟件、可移植性、支持面向對象、豐富的庫、規范的代碼。
Java:優點:開源性,功能強大,庫多
         缺點:編譯速度 比較慢,不完全
PHP:優點:性能很強,配合簡單,穩定,容易部署。
         缺點:函數命名不規范,駝峰法和下划線,傳參位置不一。
C:    優點:能操縱底層,能細粒度優化性能。
         缺點:1、是面向過程的,2、運行時類型檢查不可用,3、不提供命名空間功能,4、構        
         造函數和析構函數不可用。        
C#:  優點: 強大的.NET Framework托管代碼集合類,較簡單的語言特性。WEB應用程序    
         開發速度快。
         缺點:底層和高性能不合適,Windows平台以外支持有限。
C++: 優點:性能比較高,可進化型。
         缺點: 難學,門檻高

4、簡述解釋型和編譯型編程語言?

編譯型語言:
     使用專門的編譯器,針對特定的平台,將高級語言源代碼一次性的編譯成可被該平台硬件執行的機器碼,並包裝成該平台所能識別的可執行性程序的格式。
   特點:
     在編譯型語言寫的程序執行之前,需要一個專門的編譯過程,把源代碼編譯成機器語言的文件.
   執行方式:
     源代碼 ———> 編譯(一次編譯) ———>目標代碼———>執行(多次執行)———>輸出

解釋型語言:
     使用專門的解釋器對源程序逐行解釋成特定平台的機器碼並立即執行。
  特點:
     解釋型語言不需要事先編譯,其直接將源代碼解釋成機器碼並立即執行,所以只要某一平台提供了相應的解釋器即可運行該程序。
  執行方式:
    源代碼 ———> 解釋器(每次執行都需要解釋)———>輸出    

  編譯型: C c++, c#
  解釋型: python PHP ruby, java

5、Python解釋器種類以及特點?

CPython
官方版本的解釋器:CPython。這個解釋器是用C語言開發的,所以叫CPython。在命令行下運行python就是啟動CPython解釋器。CPython是使用最廣且被的Python解釋器。

IPython
IPython是基於CPython之上的一個交互式解釋器,也就是說,IPython只是在交互方式上有所增強,但是執行Python代碼的功能和CPython是完全一樣的。
CPython用>>>作為提示符,而IPython用In [序號]:作為提示符。

PyPy
PyPy是另一個Python解釋器,它的目標是執行速度。PyPy采用JIT技術,對Python代碼進行動態編譯(注意不是解釋),所以可以顯著提高Python代碼的執行速度。

絕大部分Python代碼都可以在PyPy下運行,但是PyPy和CPython有一些是不同的,這就導致相同的Python代碼在兩種解釋器下執行可能會有不同的結果。如果你的代碼要放到PyPy下執行,就需要了解PyPy和CPython的不同點。

Jython
Jython是運行在Java平台上的Python解釋器,可以直接把Python代碼編譯成Java字節碼執行。

IronPython
IronPython和Jython類似,只不過IronPython是運行在微軟.Net平台上的Python解釋器,可以直接把Python代碼編譯成.Net的字節碼。

6、位和字節的關系?

位:"位(bit)"是電子計算機中最小的數據單位。每一位的狀態只能是0或1。

字節:8個二進制位構成1個"字節(Byte)",它是存儲空間的基本計量單位。1個字節可以儲存1個英文字母或者半個漢字,換句話說,1個漢字占據2個字節的存儲空間。

7、b、B、KB、MB、GB 的關系?

b 比特bit / 位 
B——字節           1 B = 8b(8個bit/ 位)一個字節(byte)等於8位(bit)
KB——千比特      1 kB = 1024 B (kB - kilobajt) 
MB——兆比特     1 MB = 1024 kB (MB - megabajt)
GB——吉比特     1 GB = 1024 MB (GB - gigabajt) 

8、請至少列舉5個 PEP8 規范(越多越好)。

https://legacy.python.org/dev/peps/pep-0008/

https://blog.csdn.net/ratsniper/article/details/78954852

9、通過代碼實現如下轉換:

二進制轉換成十進制:v = “0b1111011”

十進制轉換成二進制:v = 18
 
八進制轉換成十進制:v = “011”
 
十進制轉換成八進制:v = 30
 
十六進制轉換成十進制:v = “0x12”
 
十進制轉換成十六進制:v = 87

# hex()轉16進制;oct()轉8進制;bin()轉二進制;int()轉十進制

# 二進制轉換成十進制
v = "0b1111011"
print(int(v, 2))   # 123

# 十進制轉換成二進制
v = 18
print(bin(v))      # 0b10010

# 八進制轉換成十進制
v = "011"
print(int(v, 8))   # 9

# 十進制轉換成八進制:
v =30
print(oct(v))      # 0o36

# 十六進制轉換成十進制
v = "0x12"
print(int(v, 16))  # 18

# 十進制轉換成十六進制:
v = 87
print(hex(v))      # 0x57 

10、請編寫一個函數實現將IP地址轉換成一個整數。

如 10.3.9.12 轉換規則為:
        10            00001010

         3            00000011

         9            00001001

        12            00001100

再將以上二進制拼接起來計算十進制結果:00001010 00000011 00001001 00001100 = ?

def ipAddr_union(ip_addr):
    li = ip_addr.split('.')
    new_li = []
    print(li)   # ['10', '3', '9', '12']
    for i in li:
        numStr = str(bin(int(i)))
        binStr = numStr.split('b')[1]
        # print(binStr)
        while len(binStr)< 8:
            binStr = '0'+binStr
        new_li.append(binStr)
    print(new_li)
    res_str = ''
    for i in new_li:
        res_str += i
    print(res_str)   # 00001010000000110000100100001100
    res_int = int(res_str, 2)
    print(res_int)   # 167971084


ipAddr_union('10.3.9.12')

11、python遞歸的最大層數?

import sys
sys.getrecursionlimit()    # 獲取最大遞歸層數  默認是1000(0-999)
sys.setrecursionlimit(1200)    # 設置最大遞歸層數

12、求結果:
    v1 = 1 or 3

    v2 = 1 and 3

    v3 = 0 and 2 and 1

    v4 = 0 and 2 or 1

    v5 = 0 and 2 or 1 or 4

    v6 = 0 or False and 1

>>>print(1 or 3)
1
>>>print(1 and 3)
3
>>>print(0 and 2 and 1)
0
>>>print(0 and 2 or 1)
1
>>>print(0 and 2 or 1 or 4)
1
>>>print(0 or False and 1)
False

13、ascii、unicode、utf-8、gbk 區別?

  

14、字節碼和機器碼的區別?

機器碼(machine code),學名機器語言指令,有時也被稱為原生碼(Native Code),是電腦的CPU可直接解讀的數據。
通常意義上來理解的話,機器碼就是計算機可以直接執行,並且執行速度最快的代碼。
用機器語言編寫程序,編程人員要首先熟記所用計算機的全部指令代碼和代碼的涵義。手編程序時,程序員得自己處理每條指令和每一數據的存儲分配和輸入輸出,還得記住編程過程中每步所使用的工作單元處在何種狀態。這是一件十分繁瑣的工作,編寫程序花費的時間往往是實際運行時間的幾十倍或幾百倍。而且,編出的程序全是些0和1的指令代碼,直觀性差,還容易出錯。現在,除了計算機生產廠家的專業人員外,絕大多數的程序員已經不再去學習機器語言了。
機器語言是微處理器理解和使用的,用於控制它的操作二進制代碼。8086到Pentium的機器語言指令長度可以從1字節到13字節。盡管機器語言好像是很復雜的,然而它是有規律的。存在着多至100000種機器語言的指令。這意味着不能把這些種類全部列出來。總結:機器碼是電腦CPU直接讀取運行的機器指令,運行速度最快,但是非常晦澀難懂,也比較難編寫,一般從業人員接觸不到。


字節碼(Bytecode)是一種包含執行程序、由一序列 op 代碼/數據對 組成的二進制文件。字節碼是一種中間碼,它比機器碼更抽象,需要直譯器轉譯后才能成為機器碼的中間代碼。
通常情況下它是已經經過編譯,但與特定機器碼無關。字節碼通常不像源碼一樣可以讓人閱讀,而是編碼后的數值常量、引用、指令等構成的序列。
字節碼主要為了實現特定軟件運行和軟件環境、與硬件環境無關。字節碼的實現方式是通過編譯器和虛擬機器。編譯器將源碼編譯成字節碼,特定平台上的虛擬機器將字節碼轉譯為可以直接執行的指令。字節碼的典型應用為Java bytecode。
字節碼在運行時通過JVM(JAVA虛擬機)做一次轉換生成機器指令,因此能夠更好的跨平台運行。
總結:字節碼是一種中間狀態(中間碼)的二進制代碼(文件)。需要直譯器轉譯后才能成為機器碼。

15、三元運算規則以及應用場景?

三元運算又稱三目運算,是對簡單的條件語句的簡寫:

為真時的結果 if 判斷條件 else 為假時的結果(注意,沒有冒號)
x = x+1 if x%2==1 else x

16、列舉 Python2和Python3的區別?

Python2默認的字符編碼是ASCII,默認的文件編碼也是ASCII ;
python3默認的字符編碼是unicode,默認的文件編碼是utf-8。

在python2里,將string處理為原生的bytes類型。
python3把字符串的編碼改成了unicode, 還把str和bytes做了明確區分, str就是unicode格式的字符,bytes是單純二進制。

print語句沒有了,取而代之的是print()函數。

在python 2.x中/除法整數相除的結果是一個整數,把小數部分完全忽略掉,浮點數除法會保留小數點的部分得到一個浮點數的結果。
在python 3.x中/除法不再這么做了,對於整數之間的相除,結果也會是浮點數。 

捕獲異常的語法由 except exc, var 改為 except exc as var。

Python 2.x 中反引號``相當於repr函數的作用
Python 3.x 中去掉了``這種寫法,只允許使用repr函數

Py3.X去除了long類型,現在只有一種整型——int,但它的行為就像2.X版本的long 

在 Python 2 中 有range()和xrange() ,一般使用xrange()創建迭代對象。
在 Python 3 中,range() 是像 xrange()那樣實現,xrange()內置函數已經刪除。

17、用一行代碼實現數值交換:
     
 a = 1
 
     b = 2

>>>a=1
>>>b=2
>>>a, b = b, a
>>>a
2
>>>b
1

18、Python3和Python2中 int 和 long的區別?

python2有非浮點數准備的int和long類型。int類型最大值不能超過sys.maxint,而且這個最大值是平台相關的。
  可以通過在數字的末尾附上一個L來定義長整型,顯然,它比int類型表示的數字范圍更大。
python3里,只有一種整數類型int,大多數情況下,和python2中的長整型類似。

19、xrange和range的區別?

python2里,有兩種方法獲得一定范圍內的數字:range(),返回一個列表,還有xrange(),返回一個迭代器。
python3里,range()返回迭代器,xrange()不再存在。

20、文件操作時:xreadlines和readlines的區別?(python2.3)

返回類型不同:
readlines()讀取所有行然后把它們作為一個字符串列表返回。
xreadlines返回的是生成器

readline()方法讀取整行,包括行結束符,並作為字符串返回;
        每次讀取一行,返回的是一個字符串對象,保持當前行的內存

21、列舉布爾值為False的常見值?

bool(0)   
bool(None)  
bool("") 
bool(())  
bool([])  
bool({}) 

22、字符串、列表、元組、字典每個常用的5個方法?

字符串:索引、查找find('e')、移除空白strip()、長度len()、替換replace('h', 'H')
列表:切片[1:4]、追加append()、插入insert()、修改li[2]="修改"、刪除remove和pop
元組:索引ages[3]、切片name[0:2]、長度len()、創建tuple、刪除del
字典:keys()返回包含字典所有key的列表;values()返回包含字典所有value列表;items()返回一個包含所有鍵值的列表;get()查看字典key對應的值;len()查看字典長度。

23、lambda表達式格式以及應用場景?

lambda函數就是可以接受任意多個參數(包括可選參數)並且返回單個表達式值得函數。
     語法:lambda [arg1 [,arg2,.....argn]]:expression
def calc(x,y):
    return x*y

# 將上述一般函數改寫為匿名函數:
lambda x,y:x*y

  應用:1.lambda函數比較輕便,即用即仍,適合完成只在一處使用的簡單功能。
     2.匿名函數,一般用來給filter,map這樣的函數式編程服務
     3.作為回調函數,傳遞給某些應用,比如消息處理。     

24、pass的作用?

1、空語句 do nothing
2、保證格式完整
3、保證語義完整

25、*arg和**kwarg作用

*args代表位置參數,它會接收任意多個參數並把這些參數作為元組傳遞給函數。

**kwargs代表的關鍵字參數,允許你使用沒有事先定義的參數名。

位置參數一定要放在關鍵字參數的前面。

作用:使用*args和**kwargs可以非常方便的定義函數,同時可以加強擴展性,以便日后的代碼維護。 

26、is和==的區別

==是python標准操作符中的比較操作符,用來比較判斷兩個對象的value(值)是否相等;

is也被叫做同一性運算符,這個運算符比較判斷的是對象間的唯一身份標識,也就是id是否相同。

27、簡述Python的深淺拷貝以及應用場景?

導入模塊:import copy
淺拷貝:copy.copy
深拷貝:copy.deepcopy
    淺拷貝指僅僅拷貝數據集合的第一層數據,深拷貝指拷貝數據集合的所有層。
   所以對於只有一層的數據集合來說深淺拷貝的意義是一樣的,比如字符串,數字,還有僅僅一層的字典、列表、元祖等. 應用:   淺拷貝在拷貝大量數據且不需要改變內部元素的值的時候,能大量的減少內存的使用;   深拷貝在拷貝大量數據的時候,需要在前后內部元素的內容進行改變的時候,可以修改拷貝出來的模板 

28、Python垃圾回收機制?

1、回收計數引用為0的對象,釋放其占用空間
2、循環垃圾回收器。釋放循環引用對象

29、Python的可變類型和不可變類型?

可變類型:list、dict、set、可變集合
不可變類型:string、int、float、tuple、不可變集合

30、求結果:

# Python 字典 fromkeys() 函數用於創建一個新字典,以序列 seq 中元素做字典的鍵,value 為字典所有鍵對應的初始值。
# dict.fromkeys(seq, value)

v = dict.fromkeys(['k1', 'k2'], [])
print(v)   # {'k1': [], 'k2': []}

v['k1'].append(666)
print(v)   # {'k1': [666], 'k2': [666]}

v['k1'] = 777
print(v)   # {'k1': 777, 'k2': [666]}

31、求結果:

def num():
    return [lambda x:i*x for i in range(4)]  # lambda表達式

print([m(2) for m in num()])   # 列表生成式
"""
[6, 6, 6, 6]
"""

a = [i+1 for i in range(10)]
print(a)
"""
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
"""

32、列舉常見的內置函數?

abs()  # 取絕對值
dict() # 把數據轉為字典
help() # 幫助
min()  # 找出最小值
max()  # 找出最大值
setattr()  # 設置屬性值
bool() # 判斷True or False(bool(0)、bool(Flase)、bool([]))
all()  # 可循環的數據集合每個元素bool()均為True;或者空列表也是True
any()  # 任意一個值是True即返回True
dir()  # 打印當前程序里的所有變量
hex()  # 轉換為16進制數
slice()  # 提前定義切片規則
divmod()  # 傳入兩個變量a、b,得到a//b結果和余數a%b
sorted()  # 列表排序sorted(li)等同於li.sort()  用法:sorted(iterable, key)

ascii(2)  # 只能返回ascii碼
enumerate([3,2,13,4])  # 返回列表的索引
input('dasd')
oct(10)  # 轉八進制
staticmethod() # 
bin(10)  # 轉二進制

open() # 文件打開
str()  # 轉字符串
isinstance()
ord('a')  # 返回97,ascii碼中'a'位置
chr(97)   # 返回'a',輸入97位置返回ascii碼對應字符
sum([1,4,5,-1,3,0])   # 計算列表求和

pow(100,2) # 返回x的y次方,10000
callable()   # 查看函數是否可以調用,還可用於判斷變量是否是函數
format()

vars()  # 打印變量名和對應的值
locals()  # 打印函數的局部變量(一般在函數內運行)
globals() # 打印全局變量

repr()  # 顯示形式變為字符串
compile() # 編譯代碼
complex() # 將一個數變為復數
'''
>>> complex(3,5)
(3,5j)
'''

round(1.2344434,2)  # 指定保留幾位小數  輸出1.23
# delattr, hasattr, getattr, setattr  # 面向對象中應用
hash()   # 把一個字符串變為一個數字
memoryview() # 大數據復制時內存映射
set()  # 把一個列表變為集合
'''
>>> set([12,5,1,7,9])
{1, 5, 7, 9, 12}
'''

33、filter、map、reduce的作用?

filter()    # 將符合條件的值過濾出來
map(lambda x:x*x , [1,2,3,4,5])    # 根據提供的函數對指定序列做映射
reduce(function, iterable[, initializer])   # 對參數序列中元素進行累積

34、一行代碼實現9*9乘法表

print("\n".join("\t".join(["%s*%s=%s" %(x,y,x*y) for y in range(1, x+1)]) for x in range(1, 10)))

35、如何安裝第三方模塊?以及用過哪些第三方模塊?

 

36、至少列舉8個常用模塊都有那些?

1、sys:用於提供對解釋器相關的訪問以及維護,並有很強的交互功能
2、time: 時間模塊
3、os:用於提供操作系統模塊
4、ashlib:用於加密相關的操作
5、random:生成隨機變量
6、pickle:用於python特有的類和pthon的數據類型間進行轉換
7、datetime:date和time的結合體
8、re:正則表達式模塊

37、re的match和search區別?

re.match 從頭開始匹配
re.search 匹配包含

match與search函數功能一樣,match匹配字符串開始的第一個位置,search是在字符串全局匹配第一個符合規則的。

38、什么是正則的貪婪匹配?

>>>re.search('ab*c', 'abcaxc')
<_sre.SRE_Match object; span=(0, 3), match='abc'>

>>>re.search('ab\D+c', 'abcaxc')
<_sre.SRE_Match object; span=(0, 6), match='abcaxc'>

貪婪匹配:正則表達式一般趨向於最大長度匹配,也就是所謂的貪婪匹配。

非貪婪匹配:就是匹配到結果就好,就少的匹配字符。

39、求結果:
 a. [ i % 2 for i in range(10) ]
 b. ( i % 2 for i in range(10) )

>>>a = [ i % 2 for i in range(10)]
>>>a
[0, 1, 0, 1, 0, 1, 0, 1, 0, 1]

>>>b= ( i % 2 for i in range(10) )
>>>b    #是生成器表達式(generator)
<generator object <genexpr> at 0x105204360>  

40、求結果:
 a. 1 or 2
 b. 1 and 2
 c. 1 < (2==2)
 d. 1 < 2 == 2

>>>1 or 2
1
>>>1 and 2
2
>>>1 < (2==2)
False
>>>1 < 2 ==2
True

41、def func(a,b=[]) 這種寫法有什么坑?

因為b是可變類型,每次調用這個方法b不會每次都初始化[]

def func(a,b=[]):
    b.append(a)
    print(b)
    
func(1)
func(1)
func(1)
"""
[1]
[1, 1]
[1, 1, 1]
"""
想每次執行只輸出[1] ,默認參數應該設置為None

42、如何實現 “1,2,3” 變成 [‘1’,’2’,’3’] ?

s = '1,2,3'

li = s.split(',')  # 指定分隔符對字符串進行切片
print(li)   # ['1', '2', '3']

43、如何實現[‘1’,’2’,’3’]變成[1,2,3] ?

li = ['1','2','3']

# 方法一:
new_li = [int(x) for x in li]
print(new_li)  # [1, 2, 3]

# 方法二:
new_li2 = list(map(lambda x:int(x), li))
print(new_li2)   # [1, 2, 3]

44、比較: a = [1,2,3] 和 b = [(1),(2),(3) ] 以及 b = [(1,),(2,),(3,) ] 的區別?

a = [1, 2, 3]
b1 = [(1), (2), (3)]
b2 = [(1,), (2,), (3,)]

for x in a: print(type(x))    # <class 'int'>
for x in b1: print(type(x))   # <class 'int'>
for x in b2: print(type(x))   # <class 'tuple'>

a和b1相同,因為只有一個元素的元祖需要加,來表示(1,)
b1表示的列表元素為整數,b2表示的列表元素是元祖

45、如何用一行代碼生成[1,4,9,16,25,36,49,64,81,100] ?

li = [x**2 for x in range(1,11)]
print(li)   # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

46、一行代碼實現刪除列表中重復的值 ?

集合的主要作用是去重和關系運算.

li = [1,1,4,7,4,9,7,9,11]
new_li = list(set(li))
print(new_li)  # [1, 4, 7, 9, 11]

47、如何在函數中設置一個全局變量 ?

def change_name():
    global name         # (不建議使用global)在函數內修改全局變量,不能放在函數內局部變量后面

48、logging模塊的作用?以及應用場景?

python的logging模塊提供了標准的日志接口,你可以通過它存儲各種格式的日志。

49、請用代碼簡單實現stack(棧)。

class Stack:
    """棧:先進后出"""
    def __init__(self):
        self.stack = []
 
    def push(self, element):
        """進棧"""
        self.stack.append(element)
 
    def pop(self):
        """出棧"""
        if len(self.stack) > 0:
            return self.stack.pop()
        else:
            print("棧已經空了")
 
    def get_top(self):
        """取棧頂"""
        if len(self.stack) > 0:  # 判斷棧是否為空
            return self.stack[-1]
        else:
            return None

50、常用字符串格式化哪幾種?

%格式化字符串操作符
print 'hello %s and %s' % ('df', 'another df')

字典形式的字符串格式化方法
print 'hello %(first)s and %(second)s' % {'first': 'df', 'second': 'another df'}

字符串格式化(format):
1、使用位置參數
    位置參數不受順序約束,且可以為{},參數索引從0開始,format里填寫{}對應的參數值。
>>> msg = "my name is {}, and age is {}"
>>> msg.format("hqs",22)
'my name is hqs, and age is 22'

2、使用關鍵字參數
    關鍵字參數值要對得上,可用字典當關鍵字參數傳入值,字典前加**即可
>>> hash = {'name':'john' , 'age': 23}
>>> msg = 'my name is {name}, and age is {age}'
>>> msg.format(**hash)
'my name is john,and age is 23'

3、填充與格式化
    :[填充字符][對齊方式 <^>][寬度]
>>> '{0:*<10}'.format(10)      # 左對齊
'10********'

51、簡述 生成器、迭代器、可迭代對象 以及應用場景?

生成器(generator):列表元素可以按照某種算法推算出來(有規律的數組),則可以在循環的過程中不斷推算出后續的元素。這種方式就不必創建完整的list,可以節省大量的空間。python中,這種一邊循環一邊計算的機制,稱為生成器:generator。

迭代器(Iterator):可以被next()函數調用並不斷返回下一個值得對象稱為迭代器(Iterator)。

可迭代對象(Iterable):可以直接作用於for循環的對象(其中包含集合數據類型:list\tuple\dict\set\str;還包含生成器表達式和生成器函數)。可以使用isinstance()判斷一個對象是否是Iterable對象。

52、用Python實現一個二分查找的函數。

def binary_search(li, val):
    """
    二分查找
    :param li: 輸入的列表(從小到大排序的列表)
    :param val: 輸入的待查找的值
    :return:
    """
    left = 0
    right = len(li) - 1
    while left < right:   # 候選區有值
        mid = (left + right) // 2   # 整除得到mid的下標
        if li[mid] == val:
            return mid   # 找到待查找的值
        elif li[mid] > val:
            # 待查找的值在mid左側
            right = mid - 1   # 更新候選區為之前的左候選區
        else:
            left = mid + 1    # 更新候選區為之前的右候選區
    else:
        # 找不到待查找的值
        return None

li = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(binary_search(li, 3))    # 2

53、談談你對閉包的理解?

在一個外函數中定義了一個內函數,內函數里運用了外函數的臨時變量,並且外函數的返回值是內函數的引用。這樣就構成了一個閉包。

通俗易懂的說法:當某個函數被當成對象返回時,夾帶了外部變量,就形成了一個閉包。
閉包存在的意義:它夾帶了外部變量(私貨)。同一個的函數夾帶了不同的私貨,就實現了不同的功能。

54、os和sys模塊的作用?

os 模塊提供了很多允許你的程序與操作系統直接交互的功能。

sys模塊能幫助程序員訪問與python解釋器聯系緊密的變量和函數。

55、如何生成一個隨機數?

random模塊可以很容易生成隨機數和隨機字符串。

random.randint(1, 100)  # 1-100之間取一個隨機數
random.randrange(1, 100)  # 1-100之間取一個隨機數
randint&randrange區別:randint包含100,randrange不包含100!!!


string模塊可以生成隨機字符串

string.digits  # 數字字符串   '0123456789'
string.ascii_letters  # 字母字符串 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
string.ascii_lowercase  # 小寫字母字符串  'abcdefghijklmnopqrstuvwxyz'
string.ascii_uppercase   # 大寫字母字符串 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
string.punctuation   # 特殊字符  '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'

56、如何使用python刪除一個文件?

os.remove()    # 刪除一個文件的方法

>>> os.remove('atm_shopmall.zip')
>>> os.listdir()
['.DS_Store', 'atm_shopmall', 'startMyPython3.0'] 

57、談談你對面向對象的理解?

OOP(Object Oriented Programing)編程是利用“類”和“對象”來創建各種模型來實現對真實世界的描述。與面向過程機械式的思維方式形成鮮明對比,面向對象更加注重對現實世界而非流程的模擬,是一種“上帝式”的思維方式。

核心就是對象二字,對象就是特征與技能的結合體。

優點:
    1、使程序更加容易擴展和易更改,使開發效率變得更高(對某個對象類屬性的修改,會立刻反映到整個體系中)   
    2、基於面向對象的程序可以使他人更加容易理解代碼邏輯。

缺點:
    編程復雜度高、可控性差(無法像面向過程程序那樣精准預測問題處理過程與結果,對象之間的交互,比較難預測最終的結果)

適用場景:
    應用於需求經常變化的軟件中,一般需求的變化都集中在用戶層,互聯網應用,企業內部軟件,游戲等都是面向對象的程序設計大顯身手的好地方。

58、Python面向對象中的繼承有什么特點?

在python中,新建的類可以繼承一個或多個父類(其他語言只能繼承一個父類),父類又可以稱為基類或者超類。

僅在python2中才分新式類和經典類,在python3中,無論是否繼承object,都默認繼承object,即python3中所有類均為新式類。

59、面向對象深度優先和廣度優先是什么?

在子類繼承多個父類時,屬性查找方式分深度優先和廣度優先兩種。

當類是經典類時,多繼承情況下,在要查找屬性不存在時,會按照深度優先方式查找下去。

當類是新式類時,多繼承情況下,在要查找屬性不存在時,會按照廣度優先方式查找下去。

60、面向對象中super的作用?

super() 函數是用於調用父類(超類)的一個方法。
  super 是用來解決多重繼承問題的,直接用類名調用父類方法在使用單繼承的時候沒問題,但是如果使用多繼承,會涉及到查找順序(MRO)、重復調用(鑽石繼承)等種種問題。
  MRO 就是類的方法解析順序表, 其實也就是繼承父類方法時的順序表。

作用:
1、根據 mro 的順序執行方法
2、主動執行Base類的方法

61、是否使用過functools中的函數?其作用是什么?

Python的functools模塊用以為可調用對象(callable objects)定義高階函數或操作。
簡單地說,就是基於已有的函數定義新的函數。 所謂高階函數,就是以函數作為輸入參數,返回也是函數。

62、列舉面向對象中帶雙下划線的特殊方法,如:__new__、__init__

__dict__:查出一個字典,所有實例共享的變量和函數,dir()的子集
__name__:查看類的名字(這里的類名是字符串類型的)
__doc__:顯示注釋
__module__:類定義所在的模塊

__init__:為對象定制自己獨有的特征
__base__:只查看從左到右繼承的第一個子類
__bases__:查看所有繼承的父類

__get__():調用一個屬性時,觸發
__set__():為一個屬性賦值時,觸發
__delete__():采用del刪除屬性時,觸發

__getitem__(self,key):返回鍵對應的值
__setitem__(self,key,value):設置給定鍵的值
__delitem__(self,key):刪除給定鍵對應的元素

__str__,__repr__:改變對象的字符串顯示
__format__:自定制格式化字符串
__call__:方法由對象后加括號觸發,即:對象() 或者 類()()

63、如何判斷是函數還是方法?

函數:函數是封裝了一些獨立的功能,可以直接調用,python內置了許多函數,同時可以自建函數來使用。

方法:方法和函數類似,同樣封裝了獨立的功能,但是方法是需要通過對象來調用的,表示針對這個對象要做的操作,使用時采用點方法。

64、靜態方法和類方法區別?

綁定方法:綁定給誰,就應該由誰來調用,誰來調用就會把調用者當作第一個參數自動傳入

綁定到對象的方法:在類內定義的沒有被任何裝飾器修飾的,自動將對象當做第一個參數傳入(屬於類的函數,類可以調用,但是必須按照函數的規則來,沒有自動傳值那么一說)

綁定到類的方法:在類內定義的被裝飾器@classmethod修飾的方法。自動將類當做第一個參數傳入(其實對象也可以調用,但仍將類作為第一個參數傳入)

非綁定方法:在類中用@staticmethod裝飾器裝飾的方法。不與類或對象綁定,類和對象都可以調用,但是沒有自動傳值那么一說。

65、列舉面向對象中的特殊成員以及應用場景

1. __doc__ #輸出:類的描述信息

2. __module__ 和 __class__
  __module__ 表示當前操作的對象在那個模塊
  __class__ 表示當前操作的對象的類是什么

3. __init__
  構造方法,通過類創建對象時,自動觸發執行。

4. __del__
  析構方法,當對象在內存中被釋放時,自動觸發執行。

5. __call__
  對象后面加括號,觸發執行。即: 對象() 或 類()()

class Foo:
    def __init__(self):
        pass

    def __call__(self, *args, **kwargs):
        print('__call__')


obj = Foo()  # 執行 __init__
obj()  # 執行 __call__

6. __dict__ 類或對象中的所有成員

7. __str__
  如果一個類中定義了__str__方法,那么在打印 對象 時,默認輸出該方法的返回值。

8. __getitem__ __setitem__ __delitem__
  類似字典一樣索引的操作,以上分別表示獲取,設置,刪除。(當在類外面做了這些操作后觸發這些函數,甚至可刪除不存在的數據)

class Foo(object):
    def __getitem__(self, key):
        print('__getitem__',key)
    def __setitem__(self, key, value):
        print('__setitem__',key,value)
    def __delitem__(self, key):
        print('__delitem__',key)

obj = Foo()

result = obj["k1"]          # 自動觸發執行 __getitem__
obj['k2'] = 'wupeiqi'      # 自動觸發執行 __setitem__
del obj['k1']              # 自動觸發執行 __delitem__

__getitem__ k1
__setitem__ k2 wupeiqi
__delitem__ k1

9. __new__ 用來將類實例化的

def __new__(cls,*args,**kwargs):   #重構__new__方法:在實例化之前做些事情
    print("Foo --new--")
    return object.__new__(cls)     #繼承父類的__new__方法(此時cls是一個對象)

66、1、2、3、4、5 能組成多少個互不相同且無重復的三位數

li = [1, 2, 3, 4, 5]
new_li = []

for i in li :
    for j in li:
        for m in li:
            if i != j and i != m and j != m:
                num_str = str(i)+str(j)+str(m)
                num = int(num_str)
                new_li.append(num)

new_set = set(new_li)
new_list = list(new_set)
new_list.sort()
print(new_list)
print(len(new_list))    # 60   5*4*3

67、什么是反射?以及應用場景?

反射的概念是由Smith在1982年首次提出的,主要是指程序可以訪問、檢測和修改它本身狀態或行為的一種能力(自省)。
python面向對象中的反射:通過字符串的形式操作對象相關的屬性。python中的一切事物都是對象(都可以使用反射)

四個實現反射的函數:
hasattr(object,name)   # 判斷object中有沒有一個name字符串對應的方法或屬性
getattr(object, name, default=None)   # 獲取屬性
setattr(x, y, v)   # 設置屬性
delattr(x, y)   # 刪除屬性

  實現可插拔機制,常用於web框架的CBV配置文件獲取類。

68、metaclass作用?以及應用場景?***

元類是類的類,是類的模板。
元類作用:是控制如何創建類的,正如類是創建對象的模板一樣,而元類的主要目的是為了控制類的創建行為。

69、用盡量多的方法實現單例模式。

# 單例:即單個實例,指的是同一個類實例化多次的結果指向同一個對象,用於節省內存空間
# 如果我們從配置文件中讀取配置來進行實例化,在配置相同的情況下,就沒必要重復產生對象浪費內存了
#settings.py文件內容如下
HOST='1.1.1.1'
PORT=3306

#方式一:定義一個類方法實現單例模式
import settings

class Mysql:
    __instance=None
    def __init__(self,host,port):
        self.host=host
        self.port=port

    @classmethod
    def singleton(cls):
        if not cls.__instance:
            cls.__instance=cls(settings.HOST,settings.PORT)
        return cls.__instance


obj1=Mysql('1.1.1.2',3306)
obj2=Mysql('1.1.1.3',3307)
print(obj1 is obj2) #False

obj3=Mysql.singleton()
obj4=Mysql.singleton()
print(obj3 is obj4) #True



#方式二:定制元類實現單例模式
import settings

class Mymeta(type):
    def __init__(self,name,bases,dic): #定義類Mysql時就觸發

        # 事先先從配置文件中取配置來造一個Mysql的實例出來
        self.__instance = object.__new__(self)  # 產生對象
        self.__init__(self.__instance, settings.HOST, settings.PORT)  # 初始化對象
        # 上述兩步可以合成下面一步
        # self.__instance=super().__call__(*args,**kwargs)


        super().__init__(name,bases,dic)

    def __call__(self, *args, **kwargs): #Mysql(...)時觸發
        if args or kwargs: # args或kwargs內有值
            obj=object.__new__(self)
            self.__init__(obj,*args,**kwargs)
            return obj

        return self.__instance




class Mysql(metaclass=Mymeta):
    def __init__(self,host,port):
        self.host=host
        self.port=port



obj1=Mysql() # 沒有傳值則默認從配置文件中讀配置來實例化,所有的實例應該指向一個內存地址
obj2=Mysql()
obj3=Mysql()

print(obj1 is obj2 is obj3)

obj4=Mysql('1.1.1.4',3307)



#方式三:定義一個裝飾器實現單例模式
import settings

def singleton(cls): #cls=Mysql
    _instance=cls(settings.HOST,settings.PORT)

    def wrapper(*args,**kwargs):
        if args or kwargs:
            obj=cls(*args,**kwargs)
            return obj
        return _instance

    return wrapper


@singleton # Mysql=singleton(Mysql)
class Mysql:
    def __init__(self,host,port):
        self.host=host
        self.port=port

obj1=Mysql()
obj2=Mysql()
obj3=Mysql()
print(obj1 is obj2 is obj3) #True

obj4=Mysql('1.1.1.3',3307)
obj5=Mysql('1.1.1.4',3308)
print(obj3 is obj4) #False

70、裝飾器的寫法以及應用場景。

import datetime

def log(func):   # 裝飾器接受一個函數作為參數,並返回一個函數
    def wrapper(*args, **kw):
        print('call %s(): ' % func.__name__)
        return func(*args, **kw)
    return wrapper

@log  # 運用@語法把裝飾器放置在函數定義處
def now():
    print(datetime.datetime.now())

now()
"""
call now(): 
2018-03-20 23:00:05.201096
"""

# 應用場景:Django的csrf,緩存,登錄認證,Falsk中的許多裝飾器

71、異常處理寫法以及如何主動跑出異常(應用場景)

try:
    """執行語句"""
except: #異常類型
    """觸發異常后執行的語句"""
finally:
    """有沒有異常都執行的語句"""
# 主動拋出異常
raise  #異常類實例

72、什么是面向對象的mro

對於你定義的每一個類,python會計算出一個方法解析順序(MRO)列表,這個MRO列表就是一個簡單的所有基類的線性順序列表。

python會在MRO列表上從左到右開始查找基類,直到找到第一個匹配這個屬性的類為止。

73、isinstance作用以及應用場景?

isinstance(obj,cls)檢查obj是否是類 cls 的對象

74、寫代碼並實現:
Given an array of integers, return indices of the two numbers such that they add up to a specific target.You may assume that each input would 
have exactly one solution, and you may not use the same element twice.
Example:

          Given nums = [2, 7, 11, 15], target = 9,
           
Because nums[0] + nums[1] = 2 + 7 = 9,

           return [0, 1]

 

75、json序列化時,可以處理的數據類型有哪些?如何定制支持datetime類型?

json只能支持int\str\list\tuple\dict

import json, datetime
from json import JSONEncoder

class ComplexEncoder(JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            return obj.strftime('%Y-%m-%d %H:%M:%S')
        else:
            return super(ComplexEncoder, self).default(obj)

d = {'name': 'alex', 'data': datetime.datetime.now()}
print(json.dumps(d, cls=ComplexEncoder))   
# {"name": "alex", "data": "2018-09-28 14:49:42"}

76、json序列化時,默認遇到中文會轉換成unicode,如果想要保留中文怎么辦?

import json

a = json.dumps({"ddf": "你好"}, ensure_ascii=False)
print(a)
# {"ddf": "你好"}

77、什么是斷言?應用場景?

assert斷言——聲明其布爾值必須為真判定,發生異常則為假。

info = {}
info['name'] = 'egon'
info['age'] = 18

# if 'name' not in info:
#     raise KeyError('必須有name這個key')
#
# if 'age' not in info:
#     raise KeyError('必須有age這個key')

# 用assert取代上述代碼:
assert ('name' in info) and ('age' in info)

設置一個斷言目的就是要求必須實現某個條件。

78、有用過with statement嗎?它的好處是什么?

with語句的作用是通過某種方式簡化異常處理,它是所謂的上下文管理器的一種

用法舉例如下:

 with open('output.txt', 'w') as f:
        f.write('Hi there!')

    當你要成對執行兩個相關的操作的時候,這樣就很方便,以上便是經典例子,with語句會在嵌套的代碼執行之后,自動關閉文件。

這種做法的還有另一個優勢就是,無論嵌套的代碼是以何種方式結束的,它都關閉文件。
  如果在嵌套的代碼中發生異常,它能夠在外部exception handler catch異常前關閉文件。
  如果嵌套代碼有return/continue/break語句,它同樣能夠關閉文件。

79、使用代碼實現查看列舉目錄下的所有文件。

import os

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
print(BASE_DIR)
print(os.listdir(BASE_DIR))
"""
/Users/hqs/PycharmProjects/日常練習
['字符串倒序.py', '學生類統計實例化個數.py', '類計算器.py', '生成器日志調用.py', 'lamba_test.py']
"""

80、簡述 yield和yield from關鍵字。

當一個函數中出現yield關鍵字的時候,那么這個函數就是一個生成器(generator)。
函數轉化為generator后,在每次調用next()的時候執行,遇到yield語句返回,再次執行時從上次返回的yield語句處繼續執行。

yield from iterable就是for item in iterable: yield item的語法糖。
注意yield from 后面一定是可迭代對象(iterable)。

 


免責聲明!

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



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