什么網(wǎng)站可以自己做配圖軟文營(yíng)銷(xiāo)
Python面試筆記
- Python
- Q. Python中可變數(shù)據(jù)類(lèi)型與不可變數(shù)據(jù)類(lèi)型,淺拷貝與深拷貝詳解
- Q. 解釋什么是lambda函數(shù)?它有什么好處?
- Q. 什么是裝飾器?
- Q. 什么是Python的垃圾回收機(jī)制?
- Q. Python內(nèi)置函數(shù)dir的用法?
- Q. Python中兩邊都有下劃線(xiàn)的方法有什么含義?
- Q. Python中單下劃線(xiàn)和雙下劃線(xiàn)的區(qū)別
- Q. __new__和__init__區(qū)別
- Q. 什么是迭代器和?成器?
- Q. 什么是異常處理?
- Q. Python斷言(assert)
- Q. Python中`*` 和 `**`用法?
Python
Q. Python中可變數(shù)據(jù)類(lèi)型與不可變數(shù)據(jù)類(lèi)型,淺拷貝與深拷貝詳解
【Python基礎(chǔ)】Python的深淺拷貝講解
Q. 解釋什么是lambda函數(shù)?它有什么好處?
Lambda函數(shù)是Python中的匿名函數(shù)。
Lambda函數(shù)在Python中被廣泛使用,主要是因?yàn)樗鼈兲峁┝艘环N快速定義單行最小函數(shù)的方式,而無(wú)需使用常規(guī)的def關(guān)鍵字。這種函數(shù)通常用于需要一個(gè)簡(jiǎn)單操作的地方,例如在列表推導(dǎo)式、map()、filter()等高階函數(shù)中作為參數(shù)傳遞。Lambda函數(shù)的基本語(yǔ)法結(jié)構(gòu)是:lambda parameters_list: expression,其中parameters_list是函數(shù)的參數(shù)列表,而expression則是基于這些參數(shù)的表達(dá)式,該表達(dá)式的結(jié)果將被返回。
Lambda函數(shù)的優(yōu)點(diǎn)主要包括代碼簡(jiǎn)潔、無(wú)需增加額外變量、即時(shí)定義與使用。具體內(nèi)容如下:
- 代碼簡(jiǎn)潔:由于lambda函數(shù)通常只包含一個(gè)表達(dá)式,因此代碼非常簡(jiǎn)潔,可以提高代碼的可讀性。
- 無(wú)需增加額外變量:因?yàn)閘ambda函數(shù)是匿名的,所以不需要為其分配一個(gè)名字,這有助于減少程序中的變量數(shù)量,避免命名沖突。
- 即時(shí)定義與使用:可以在需要時(shí)立刻定義并使用,不必像常規(guī)函數(shù)那樣先定義再調(diào)用。
# case 1
add = lambda x, y: x + y
result = add(3, 5)
print(result) # 輸出:8
# case 2
students = [("Alice", 25), ("Bob", 20), ("Charlie", 30)]
students.sort(key=lambda student: student[1])
print(students) # 輸出:[('Bob', 20), ('Alice', 25), ('Charlie', 30)]
# case 3
numbers = [1, 2, 3, 4, 5, 6]
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(even_numbers) # 輸出:[2, 4, 6]
Lambda表達(dá)式通常?于需要傳遞函數(shù)作為參數(shù)的函數(shù)(例如 map
、 filter
、 sorted
等),或
者在需要定義?常簡(jiǎn)單的匿名函數(shù)時(shí)。
總之,盡管lambda函數(shù)有許多優(yōu)點(diǎn),但它們也受到一些限制,如只能包含一個(gè)表達(dá)式,不能包含復(fù)雜的邏輯或語(yǔ)句,且沒(méi)有文檔字符串和名稱(chēng)。因此,在決定是否使用lambda函數(shù)時(shí),應(yīng)當(dāng)根據(jù)實(shí)際需求和上下文進(jìn)行權(quán)衡。
Q. 什么是裝飾器?
裝飾器本質(zhì)上是一個(gè)Python函數(shù),它可以讓其他函數(shù)在不需要做任何代碼變動(dòng)的前提下增加額外功能,裝飾器的返回值也是一個(gè)函數(shù)對(duì)象。它經(jīng)常用于有切面需求的場(chǎng)景,比如:插入日志、性能測(cè)試、事務(wù)處理、緩存、權(quán)限校驗(yàn)等場(chǎng)景。裝飾器是解決這類(lèi)問(wèn)題的絕佳設(shè)計(jì),有了裝飾器,我們就可以抽離出大量與函數(shù)功能本身無(wú)關(guān)的雷同代碼并繼續(xù)重用。
def my_decorator(func): def wrapper(): print("Something is happening before the function is called.") func() print("Something is happening after the function is called.") return wrapper @my_decorator
def say_hello(): print("Hello!") # 當(dāng)調(diào)用 say_hello 時(shí),實(shí)際上是調(diào)用了裝飾器返回的 wrapper 函數(shù)
say_hello()輸出:
Something is happening before the function is called.
Hello!
Something is happening after the function is called.
Q. 什么是Python的垃圾回收機(jī)制?
Python的垃圾回收機(jī)制主要負(fù)責(zé)自動(dòng)管理內(nèi)存,釋放不再使用的對(duì)象所占用的內(nèi)存空間。
Python的垃圾回收機(jī)制主要包括以下幾種:
- 引用計(jì)數(shù)(Reference Counting)。這是Python中最基本的垃圾回收方法。每個(gè)對(duì)象都有一個(gè)引用計(jì)數(shù),記錄有多少個(gè)變量指向該對(duì)象。當(dāng)引用計(jì)數(shù)為0時(shí),表示該對(duì)象不再被使用,可以被回收。
- 標(biāo)記-清除(Mark and Sweep)。這種方法用于處理循環(huán)引用的情況。當(dāng)內(nèi)存空間即將被占滿(mǎn)時(shí),Python會(huì)暫停程序,從頭到尾掃描所有對(duì)象,并標(biāo)記所有可達(dá)的對(duì)象。然后,清除所有未被標(biāo)記的對(duì)象,回收它們占用的內(nèi)存空間。
- 分代回收(Generational Collection)。為了提高垃圾回收的效率,Python引入了分代回收機(jī)制。對(duì)象被分為不同的代,如第0代和第1代等。新創(chuàng)建的對(duì)象通常放在第0代,而經(jīng)過(guò)多次垃圾回收仍然存活的對(duì)象會(huì)被提升到更高的代。垃圾回收器會(huì)更多地檢查低代中的對(duì)象,而對(duì)高代中的對(duì)象進(jìn)行較少的檢查,從而提高垃圾回收的效率。
需要注意的是,Python的垃圾回收機(jī)制是自動(dòng)進(jìn)行的,開(kāi)發(fā)者不需要手動(dòng)管理內(nèi)存。垃圾回收器會(huì)根據(jù)需要定期啟動(dòng),并在合適的時(shí)機(jī)回收不再使用的對(duì)象。
Q. Python內(nèi)置函數(shù)dir的用法?
在 Python 中,dir() 是一個(gè)內(nèi)置函數(shù),用于查找對(duì)象的所有屬性和方法。它返回一個(gè)字符串列表,包含了對(duì)象的所有屬性和方法的名稱(chēng)。
class MyClass:def __init__(self):self.name = "John"def say_hello(self):print("Hello, world!")obj = MyClass()print("對(duì)象 obj 的屬性和方法:", dir(obj))輸出:
對(duì)象 obj 的屬性和方法: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name', 'say_hello']
Q. Python中兩邊都有下劃線(xiàn)的方法有什么含義?
在Python中,兩邊都有雙下劃線(xiàn)的方法名被稱(chēng)為魔法方法(magic methods)。這些方法是Python語(yǔ)言的基礎(chǔ),它們?yōu)镻ython提供了強(qiáng)大的內(nèi)置功能。例如,__init__
方法是類(lèi)的構(gòu)造函數(shù),__str__
方法定義了對(duì)象被轉(zhuǎn)換為字符串時(shí)的行為。
以下是一個(gè)簡(jiǎn)單的類(lèi)示例,它定義了一個(gè)帶有兩邊都有雙下劃線(xiàn)的方法:
class MyClass:def __init__(self, value):self.value = valuedef __str__(self):return f"MyClass with value: {self.value}"# 使用類(lèi)
obj = MyClass(10)
print(obj) # 輸出: MyClass with value: 10
Python中還有很多其他的魔法方法,以下是一些常用的魔法方法:
__init__
:構(gòu)造函數(shù),當(dāng)一個(gè)對(duì)象被創(chuàng)建時(shí)會(huì)自動(dòng)調(diào)用。
__del__
:析構(gòu)函數(shù),當(dāng)一個(gè)對(duì)象被銷(xiāo)毀時(shí)會(huì)自動(dòng)調(diào)用。
__str__
:返回一個(gè)對(duì)象的字符串表示,通常用于print函數(shù)。
__repr__
:返回一個(gè)對(duì)象的官方字符串表示,通常用于調(diào)試。
__call__
:允許一個(gè)對(duì)象像函數(shù)那樣被調(diào)用。
__getitem__
、__setitem__
、__delitem__
:用于自定義索引操作,如obj[key]。
__len__
:返回對(duì)象的長(zhǎng)度,常用于len()函數(shù)。
__iter__
:返回一個(gè)迭代器,用于遍歷對(duì)象。
__enter__
和 __exit__
:用于實(shí)現(xiàn)上下文管理協(xié)議,如with語(yǔ)句。
__add__
、__sub__
、__mul__
等:用于自定義算術(shù)運(yùn)算符的行為。
這些魔法方法允許你自定義Python對(duì)象的行為,使其更符合你的需求。你可以根據(jù)需要實(shí)現(xiàn)這些方法來(lái)擴(kuò)展Python類(lèi)的功能。
Q. Python中單下劃線(xiàn)和雙下劃線(xiàn)的區(qū)別
- “單下劃線(xiàn)” 開(kāi)始的成員變量叫做保護(hù)變量,意思是只有類(lèi)對(duì)象和子類(lèi)對(duì)象自己能訪(fǎng)問(wèn)到這些變量,需通過(guò)類(lèi)提供的接口進(jìn)行訪(fǎng)問(wèn),不能用“from xxx import *”而導(dǎo)入;
- “雙下劃線(xiàn)” 開(kāi)始的是私有成員,意思是只有類(lèi)對(duì)象自己能訪(fǎng)問(wèn),連子類(lèi)對(duì)象也不能訪(fǎng)問(wèn)到這個(gè)數(shù)據(jù)。仍然可以通過(guò)_{classname}__name來(lái)訪(fǎng)問(wèn)__name變量。但是強(qiáng)烈建議你不要這么干,因?yàn)椴煌姹镜腜ython解釋器可能會(huì)把__name改成不同的變量名。
Q. __new__和__init__區(qū)別
__new__與__init__區(qū)別總共有四個(gè)方面:
- 功能上的區(qū)別: 前者生成類(lèi)實(shí)例對(duì)象空間的,后者是初始化對(duì)象空間并給對(duì)象賦值的;
- 執(zhí)行順序: 先執(zhí)行__new__方法生成類(lèi)對(duì)象空間才能執(zhí)行后者
- 返回值: 前者有返回值,后者沒(méi)有返回值
- 前者是靜態(tài)方法, 后者是構(gòu)造方法。
Q. 什么是迭代器和?成器?
迭代器(Iterator)和?成器(Generator)都是Python中?于處理迭代的重要概念,允許逐個(gè)訪(fǎng)問(wèn)數(shù)據(jù)項(xiàng),??需將所有數(shù)據(jù)加載到內(nèi)存中,這在處理?型數(shù)據(jù)集合時(shí)?常有?。盡管有?些相似之處,但在實(shí)現(xiàn)和?法上有?些關(guān)鍵的區(qū)別。
1.迭代器(Iterator)
迭代器是?個(gè)對(duì)象,它可以通過(guò)調(diào)? __next__()
?法逐個(gè)返回集合中的元素。迭代器通常?于遍
歷集合,如列表、元組、字典等,以及?定義的可迭代對(duì)象。的核?特點(diǎn)是惰性計(jì)算,即只在需要時(shí)才計(jì)算下?個(gè)元素。
Python的內(nèi)置函數(shù) iter() 可以?于將可迭代對(duì)象轉(zhuǎn)換為迭代器,? next() 函數(shù)?于獲取迭代
器的下?個(gè)元素。當(dāng)沒(méi)有更多元素可供迭代時(shí),迭代器會(huì)引發(fā) StopIteration 異常。
numbers = [1, 2, 3, 4, 5]
iter_numbers = iter(numbers)
print(next(iter_numbers)) # 輸出:1
print(next(iter_numbers)) # 輸出:2
2.生成器(Generator)
生成器是?種特殊的迭代器,它可以通過(guò)函數(shù)來(lái)創(chuàng)建。?成器函數(shù)使? yield
關(guān)鍵字來(lái)產(chǎn)?值,并且會(huì)保持函數(shù)的狀態(tài),以便在下?次調(diào)?時(shí)繼續(xù)執(zhí)?。?成器允許按需?成數(shù)據(jù),?不必將所有數(shù)據(jù)存儲(chǔ)在內(nèi)存中。
?成器有兩種創(chuàng)建?式:
- 使??成器函數(shù):定義?個(gè)函數(shù),其中包含 yield 語(yǔ)句來(lái)?成值。
def countdown(n):while n > 0:yield nn -= 1
gen = countdown(5)
for num in gen:print(num)
- 使??成器表達(dá)式:類(lèi)似于列表推導(dǎo)式,但是使?圓括號(hào)?不是?括號(hào),并且按需?成數(shù)據(jù)。
gen = (x for x in range(5))
for num in gen:print(num)
?成器通常?于處理?型數(shù)據(jù)集或需要逐個(gè)?成數(shù)據(jù)的情況,因?yàn)?strong>不需要?次性加載所有數(shù)據(jù)到內(nèi)存中,從?節(jié)省了內(nèi)存資源。
總之,迭代器和?成器都是處理迭代的強(qiáng)??具,允許?效地處理?型數(shù)據(jù)集和按需?成數(shù)據(jù)??梢愿鶕?jù)任務(wù)的需求選擇使?哪種?式。
Q. 什么是異常處理?
異常處理是?種編程技術(shù),?于在程序執(zhí)?期間捕獲、處理和處理可能發(fā)?的異常情況或錯(cuò)誤。異常是指在程序執(zhí)?過(guò)程中出現(xiàn)的不正常情況,可能導(dǎo)致程序崩潰或產(chǎn)?不可預(yù)料的結(jié)果。異常處理的?標(biāo)是使程序能夠優(yōu)雅地應(yīng)對(duì)異常情況,?不是因異常?終?或崩潰。
在Python中,異常處理通常使? try 和 except 語(yǔ)句來(lái)實(shí)現(xiàn)。基本的異常處理結(jié)構(gòu)如下:
try:# 可能引發(fā)異常的代碼塊
except ExceptionType:# 處理異常的代碼塊
- try 語(yǔ)句塊包含可能引發(fā)異常的代碼,它會(huì)被監(jiān)視以檢查是否發(fā)?異常。
- 如果在 try 塊中的代碼引發(fā)了指定類(lèi)型的異常( ExceptionType ),則程序?qū)⑻D(zhuǎn)到與該異常匹配的 except 塊,執(zhí)?異常處理代碼。
- 如果在 try 塊中沒(méi)有引發(fā)異常,則 except 塊將被跳過(guò),程序?qū)⒗^續(xù)執(zhí)? try 塊之后的代碼。
try:num = int(input("請(qǐng)輸??個(gè)整數(shù):"))result = 10 / num
except ZeroDivisionError:print("除以零錯(cuò)誤")
except ValueError:print("輸?不是有效的整數(shù)")
else:print("結(jié)果是:", result)
finally:print("結(jié)束")
- else語(yǔ)句塊中的代碼會(huì)在try塊沒(méi)有拋出任何異常的情況下運(yùn)行。
- finally語(yǔ)句塊中的代碼無(wú)論是否發(fā)生異常都會(huì)被執(zhí)行。
Q. Python斷言(assert)
Python assert(斷言)用于判斷一個(gè)表達(dá)式,在表達(dá)式條件為 false 的時(shí)候觸發(fā)異常。
斷言可以在條件不滿(mǎn)足程序運(yùn)行的情況下直接返回錯(cuò)誤,而不必等待程序運(yùn)行后出現(xiàn)崩潰的情況,例如我們的代碼只能在 Linux 系統(tǒng)下運(yùn)行,可以先判斷當(dāng)前系統(tǒng)是否符合條件。
語(yǔ)法格式如下:
assert expression
#等價(jià)于:
if not expression:raise AssertionError#assert后面也可以緊跟參數(shù):assert expression [, arguments]
#等價(jià)于:
if not expression:raise AssertionError(arguments)
例子:
>>> assert True # 條件為 true 正常執(zhí)行
>>> assert False # 條件為 false 觸發(fā)異常
Traceback (most recent call last):File "<stdin>", line 1, in <module>
AssertionError
>>> assert 1==1 # 條件為 true 正常執(zhí)行
>>> assert 1==2 # 條件為 false 觸發(fā)異常
Traceback (most recent call last):File "<stdin>", line 1, in <module>
AssertionError>>> assert 1==2, '1 不等于 2'
Traceback (most recent call last):File "<stdin>", line 1, in <module>
AssertionError: 1 不等于 2
>>>
Q. Python中*
和 **
用法?
在 Python 中,*
和 **
具有語(yǔ)法多義性,具體來(lái)說(shuō)是有四類(lèi)用法。
1.算數(shù)運(yùn)算
>>> 2 * 5 #乘法
//10
>>> 2 ** 5 #乘方
//32
2.函數(shù)形參
*args
和 **kwargs
主要用于函數(shù)定義。
你可以將不定數(shù)量的參數(shù)傳遞給一個(gè)函數(shù)。不定的意思是:預(yù)先并不知道, 函數(shù)使用者會(huì)傳遞多少個(gè)參數(shù)給你, 所以在這個(gè)場(chǎng)景下使用這兩個(gè)關(guān)鍵字。其實(shí)并不是必須寫(xiě)成 *args
和 **kwargs
。 *(星號(hào)) 才是必須的. 你也可以寫(xiě)成 *ar
和 **k
。而寫(xiě)成 *args
和**kwargs
只是一個(gè)通俗的命名約定。
python函數(shù)傳遞參數(shù)的方式有兩種:
- 位置參數(shù)(positional argument)
- 關(guān)鍵詞參數(shù)(keyword argument)
*args
與 **kwargs
的區(qū)別,兩者都是 python 中的可變參數(shù):
*args
表示任何多個(gè)無(wú)名參數(shù),它本質(zhì)是一個(gè) tuple**kwargs
表示關(guān)鍵字參數(shù),它本質(zhì)上是一個(gè) dict
如果同時(shí)使用 *args
和 **kwargs
時(shí),必須 *args
參數(shù)列要在 **kwargs
之前。
>>> def fun(*args, **kwargs):
... print('args=', args)
... print('kwargs=', kwargs)
...
>>> fun(1, 2, 3, 4, A='a', B='b', C='c', D='d')
//args= (1, 2, 3, 4)
//kwargs= {'A': 'a', 'B': 'b', 'C': 'c', 'D': 'd'}
使用*args
:
>>> def fun(name, *args):
... print('你好:', name)
... for i in args:
... print("你的寵物有:", i)
...
>>> fun("Geek", "dog", "cat")
//你好: Geek
//你的寵物有: dog
//你的寵物有: cat
使用 **kwargs
:
>>> def fun(**kwargs):
... for key, value in kwargs.items():
... print("{0} 喜歡 {1}".format(key, value))
...
>>> fun(Geek="cat", cat="box")
//Geek 喜歡 cat
//cat 喜歡 box
3.函數(shù)實(shí)參(解引用)
如果函數(shù)的形參是定長(zhǎng)參數(shù),也可以使用 *args
和 **kwargs
調(diào)用函數(shù),類(lèi)似對(duì)元組和字典進(jìn)行解引用:
>>> def fun(data1, data2, data3):
... print("data1: ", data1)
... print("data2: ", data2)
... print("data3: ", data3)
...
>>> args = ("one", 2, 3)
>>> fun(*args)
data1: one
data2: 2
data3: 3
>>> kwargs = {"data3": "one", "data2": 2, "data1": 3}
>>> fun(**kwargs)
data1: 3
data2: 2
data3: one
4.序列解包
序列解包沒(méi)有**
>>> a, b, *c = 0, 1, 2, 3
>>> a
0
>>> b
1
>>> c
[2, 3]