深度學(xué)習(xí)面試題專(zhuān)欄14-python
01 python標(biāo)準(zhǔn)數(shù)據(jù)類(lèi)型
02?雙下劃線和單下劃線的區(qū)別
03?自省解釋一下
04?迭代器和生成器的區(qū)別
05?裝飾器怎么用?裝飾器解釋下,基本要求是什么?
06 深拷貝和淺拷貝的區(qū)別
07 多線程和多進(jìn)程的區(qū)別?
08 is ==
09?+和join的區(qū)別
10 字典和json字符串相互轉(zhuǎn)化方法
01?python標(biāo)準(zhǔn)數(shù)據(jù)類(lèi)型
數(shù)字 (Numbers)
整型 (Integers): 如
1
,-10
,10000
。浮點(diǎn)型 (Floats): 如
3.14
,-0.001
,2.71
。復(fù)數(shù) (Complex Numbers): 如
3+4j
,-1.2+0.5j
。字符串 (Strings)
示例:
'hello'
,"world"
,'''This is a multi-line string.'''
列表 (Lists)
是一個(gè)有序集合,可以修改,并且可以包含任意類(lèi)型的元素。
示例:
[1, 2, 3]
,['apple', 'banana', 'cherry']
,[1, 'apple', 3.14]
元組 (Tuples)
與列表類(lèi)似,但它是不可變的,這意味著你不能增加、刪除或修改元組中的元素。
示例:
(1, 2, 3)
,('apple', 'banana', 'cherry')
集合 (Sets)
是一個(gè)無(wú)序的,不重復(fù)的元素集。
示例:
{1, 2, 3}
,{'apple', 'banana', 'cherry'}
字典 (Dictionaries)
由鍵值對(duì)組成,鍵必須是唯一的。
示例:
{'name': 'John', 'age': 25}
,{1: 'apple', 2: 'banana'}
布爾 (Booleans)
表示真或假的值,主要用于條件測(cè)試。
只有兩個(gè)布爾值:
True
和False
。None 類(lèi)型
這是一個(gè)特殊的常量,表示空值或者無(wú)值。
通常用于函數(shù)中返回一個(gè)空的結(jié)果或?yàn)樽兞恐付ㄒ粋€(gè)初始的“空”狀態(tài)。
02?雙下劃線和單下劃線的區(qū)別
單下劃線前綴
_variable
:這是一個(gè)約定,用于指示該變量是“私有的”。這意味著它只應(yīng)在該類(lèi)或模塊內(nèi)部使用,不應(yīng)該從外部訪問(wèn)。然而,這僅僅是一個(gè)約定,實(shí)際上并不會(huì)阻止你從外部訪問(wèn)它。
例如:
_private_var
單下劃線后綴
variable_
:當(dāng)變量名與 Python 關(guān)鍵字沖突時(shí),通常使用這種命名方式。
例如,如果你想命名一個(gè)變量為
class
(這是一個(gè) Python 關(guān)鍵字),你可以命名它為class_
。雙下劃線前綴
__variable
:當(dāng)一個(gè)變量以?xún)蓚€(gè)下劃線為前綴但不以?xún)蓚€(gè)下劃線為后綴時(shí),它會(huì)在內(nèi)部名稱(chēng)改變(Name Mangling)。這是為了確保它在子類(lèi)中不會(huì)被意外覆蓋。
這意味著,如果你有一個(gè)名為
__private_var
的變量在一個(gè)名為MyClass
的類(lèi)中,那么實(shí)際上它可以通過(guò)_MyClass__private_var
來(lái)訪問(wèn)。這種特性通常用于確保類(lèi)的私有屬性和方法不被子類(lèi)意外覆蓋或訪問(wèn)。
雙下劃線前綴和后綴
__variable__
:這樣的變量通常是 Python 的特殊方法或?qū)傩?,例?
__init__
或__len__
。這些方法有特定的意義和用途。通常不建議在自定義的屬性或方法中使用這種命名約定,除非你確實(shí)想定義自己的特殊方法。
03?自省解釋一下
在編程中,自省(或反射)是指在運(yùn)行時(shí)檢查對(duì)象的類(lèi)型和內(nèi)部信息的能力。Python 作為一門(mén)動(dòng)態(tài)語(yǔ)言,為開(kāi)發(fā)者提供了強(qiáng)大的自省功能。通過(guò)自省,開(kāi)發(fā)者可以在運(yùn)行時(shí)知道對(duì)象是什么、有哪些屬性和方法。
Python 提供了多種自省工具和函數(shù),以下是一些常見(jiàn)的自省工具:
type(): 返回對(duì)象的類(lèi)型。
x = [1, 2, 3]
print(type(x))? # <class 'list'>
dir(): 返回對(duì)象的屬性列表。對(duì)于模塊,它返回模塊的屬性、函數(shù)和類(lèi)名。
x = [1, 2, 3]
print(dir(x))
id(): 返回對(duì)象的唯一標(biāo)識(shí)符,這通常是對(duì)象在內(nèi)存中的地址。
x = [1, 2, 3]
print(id(x))
getattr(): 獲取對(duì)象的屬性值。
class Example:
? ? def __init__(self):
? ? ? ? self.data = "example data"? ??
e = Example()
print(getattr(e, 'data'))? # example data
hasattr(): 檢查對(duì)象是否有給定的屬性。
class Example:
? ? def __init__(self):
? ? ? ? self.data = "example data"
? ? ? ??
e = Example()
print(hasattr(e, 'data'))? # True
.........
04?迭代器和生成器的區(qū)別
定義:
迭代器 (Iterator): 迭代器是一個(gè)實(shí)現(xiàn)了
__iter__()
和__next__()
方法的對(duì)象。__iter__()
返回迭代器自身,而__next__()
返回序列中的下一個(gè)值。生成器 (Generator): 生成器是一種使用
yield
關(guān)鍵字的函數(shù),該函數(shù)在被調(diào)用時(shí)返回一個(gè)生成器迭代器。生成器可以產(chǎn)生一個(gè)值序列,而不需要在內(nèi)存中存儲(chǔ)整個(gè)序列。實(shí)現(xiàn):
迭代器通常需要更多的工作來(lái)創(chuàng)建,因?yàn)槟阈枰獙?shí)現(xiàn)
__iter__()
和__next__()
方法。生成器使用更簡(jiǎn)潔的語(yǔ)法,只需一個(gè)函數(shù)和
yield
關(guān)鍵字。內(nèi)存使用:
生成器是更內(nèi)存友好的,因?yàn)樗辉诿看蔚鷷r(shí)產(chǎn)生一個(gè)值,而不是存儲(chǔ)整個(gè)序列。
迭代器可能根據(jù)其實(shí)現(xiàn)而變化,但通常也是按需生成值。
使用場(chǎng)景:
如果你需要一個(gè)對(duì)象來(lái)支持自定義的迭代操作,并可能包含其他功能,那么迭代器可能更合適。
如果你只需要一個(gè)簡(jiǎn)單的工具來(lái)迭代一系列的值,生成器是一個(gè)更簡(jiǎn)潔、更直觀的選擇。
生命周期:
生成器函數(shù)的執(zhí)行可以在任何步驟中被暫停,并且可以從停止的地方繼續(xù)執(zhí)行,直到生成器被完全耗盡。
迭代器通常維持其狀態(tài),直到迭代完成。
創(chuàng)建方式:
使用
yield
關(guān)鍵字的函數(shù)。使用生成器表達(dá)式,它是列表推導(dǎo)式的簡(jiǎn)化版本,使用圓括號(hào)而不是方括號(hào)。
迭代器:使用類(lèi)來(lái)實(shí)現(xiàn)
__iter__()
和__next__()
。生成器:可以通過(guò)兩種方式創(chuàng)建:
05?裝飾器怎么用?裝飾器解釋下,基本要求是什么?
裝飾器是 Python 中非常強(qiáng)大的工具,它允許開(kāi)發(fā)者在不修改現(xiàn)有函數(shù)或方法代碼的情況下,增加或修改函數(shù)的功能。這是一種遵循開(kāi)閉原則的編程技巧:對(duì)修改關(guān)閉、對(duì)擴(kuò)展開(kāi)放。
裝飾器的基本要求:
裝飾器本身是一個(gè)函數(shù)。
裝飾器函數(shù)的主要參數(shù)是你想要“裝飾”的函數(shù)或方法。
裝飾器函數(shù)返回一個(gè)新的函數(shù),這個(gè)新函數(shù)通常是一個(gè)在原始函數(shù)上執(zhí)行了一些操作的包裝函數(shù)。
使用
@
符號(hào)將裝飾器應(yīng)用到目標(biāo)函數(shù)上。
使用裝飾器的好處:
代碼重用:可以將通用功能抽象到裝飾器中,從而避免代碼重復(fù)。
代碼組織:能夠?qū)I(yè)務(wù)邏輯與其他關(guān)注點(diǎn)(如日志、計(jì)時(shí)、訪問(wèn)控制等)分離,提高代碼的可讀性和可維護(hù)性。
靈活性:可以根據(jù)需要為函數(shù)動(dòng)態(tài)地添加或刪除功能。
06?深拷貝和淺拷貝的區(qū)別
深拷貝與淺拷貝是在復(fù)制復(fù)合對(duì)象(如列表、字典等)時(shí)常會(huì)遇到的概念。它們的主要區(qū)別在于如何復(fù)制對(duì)象內(nèi)部的子對(duì)象。以下是這兩種拷貝方法之間的主要區(qū)別:
淺拷貝 (Shallow Copy):
當(dāng)執(zhí)行淺拷貝時(shí),會(huì)創(chuàng)建一個(gè)新的復(fù)合對(duì)象,但不會(huì)為原始對(duì)象內(nèi)部的子對(duì)象創(chuàng)建新的對(duì)象。而是將新復(fù)合對(duì)象中的引用指向原始對(duì)象的子對(duì)象。
如果你修改新復(fù)合對(duì)象中的子對(duì)象,原始對(duì)象中的相應(yīng)子對(duì)象也會(huì)被修改,反之亦然。
在 Python 中,
copy
模塊的copy()
函數(shù)可以實(shí)現(xiàn)淺拷貝。深拷貝 (Deep Copy):
當(dāng)執(zhí)行深拷貝時(shí),除了復(fù)制原始對(duì)象,還會(huì)為原始對(duì)象內(nèi)部的所有子對(duì)象創(chuàng)建新的對(duì)象。這樣,新復(fù)合對(duì)象與原始對(duì)象在內(nèi)存中是完全獨(dú)立的。
修改新復(fù)合對(duì)象或其子對(duì)象不會(huì)影響到原始對(duì)象及其子對(duì)象,反之亦然。
在 Python 中,
copy
模塊的deepcopy()
函數(shù)可以實(shí)現(xiàn)深拷貝。
深拷貝與淺拷貝是在復(fù)制復(fù)合對(duì)象(如列表、字典等)時(shí)常會(huì)遇到的概念。它們的主要區(qū)別在于如何復(fù)制對(duì)象內(nèi)部的子對(duì)象。以下是這兩種拷貝方法之間的主要區(qū)別:
淺拷貝 (Shallow Copy):
當(dāng)執(zhí)行淺拷貝時(shí),會(huì)創(chuàng)建一個(gè)新的復(fù)合對(duì)象,但不會(huì)為原始對(duì)象內(nèi)部的子對(duì)象創(chuàng)建新的對(duì)象。而是將新復(fù)合對(duì)象中的引用指向原始對(duì)象的子對(duì)象。
如果你修改新復(fù)合對(duì)象中的子對(duì)象,原始對(duì)象中的相應(yīng)子對(duì)象也會(huì)被修改,反之亦然。
在 Python 中,
copy
模塊的copy()
函數(shù)可以實(shí)現(xiàn)淺拷貝。深拷貝 (Deep Copy):
當(dāng)執(zhí)行深拷貝時(shí),除了復(fù)制原始對(duì)象,還會(huì)為原始對(duì)象內(nèi)部的所有子對(duì)象創(chuàng)建新的對(duì)象。這樣,新復(fù)合對(duì)象與原始對(duì)象在內(nèi)存中是完全獨(dú)立的。
修改新復(fù)合對(duì)象或其子對(duì)象不會(huì)影響到原始對(duì)象及其子對(duì)象,反之亦然。
在 Python 中,
copy
模塊的deepcopy()
函數(shù)可以實(shí)現(xiàn)深拷貝。
淺拷貝只復(fù)制對(duì)象的最外層,內(nèi)部的子對(duì)象仍然是引用。
深拷貝會(huì)復(fù)制對(duì)象及其所有嵌套的子對(duì)象。
07?多線程和多進(jìn)程的區(qū)別?
多線程(Multithreading)和多進(jìn)程(Multiprocessing)都是并發(fā)執(zhí)行技術(shù),但它們有一些基本的區(qū)別。以下是多線程和多進(jìn)程之間的主要區(qū)別:
基本單位:
線程:線程是程序中的執(zhí)行單元,通常被稱(chēng)為輕量級(jí)的進(jìn)程。一個(gè)進(jìn)程可以擁有一個(gè)或多個(gè)線程,這些線程共享進(jìn)程的內(nèi)存空間、文件句柄等資源。
進(jìn)程:進(jìn)程是操作系統(tǒng)的基本執(zhí)行單元,是一個(gè)獨(dú)立的運(yùn)行實(shí)體。每個(gè)進(jìn)程都有自己的內(nèi)存空間、資源和代碼段。
資源開(kāi)銷(xiāo):
線程:由于線程共享相同的內(nèi)存空間,創(chuàng)建、維護(hù)和上下文切換通常比進(jìn)程要快、開(kāi)銷(xiāo)更小。
進(jìn)程:進(jìn)程有自己獨(dú)立的內(nèi)存空間,所以它們的創(chuàng)建、維護(hù)和上下文切換需要更多的開(kāi)銷(xiāo)。
隔離性:
線程:由于線程在同一進(jìn)程內(nèi)共享內(nèi)存和資源,一個(gè)線程的崩潰或錯(cuò)誤可能會(huì)影響到其他線程。
進(jìn)程:進(jìn)程之間是彼此隔離的,一個(gè)進(jìn)程的崩潰或錯(cuò)誤不會(huì)影響其他進(jìn)程。
通信:
線程:由于線程共享內(nèi)存,它們之間的通信通常更為簡(jiǎn)單,可以使用共享變量、數(shù)組等進(jìn)行通信。
進(jìn)程:進(jìn)程間通信(IPC)需要特定的機(jī)制,如管道、消息隊(duì)列、套接字等。
同步:
線程:線程同步往往比進(jìn)程同步更為復(fù)雜,因?yàn)榫€程之間的資源共享可能導(dǎo)致數(shù)據(jù)競(jìng)態(tài)條件,需要使用鎖、信號(hào)量等機(jī)制來(lái)同步。
進(jìn)程:由于進(jìn)程彼此獨(dú)立,數(shù)據(jù)競(jìng)態(tài)條件較少,但仍然需要同步機(jī)制,特別是在IPC中。
全局變量:
線程:線程共享進(jìn)程的全局變量。
進(jìn)程:每個(gè)進(jìn)程都有其自己的全局變量。
08 is ==
is:
is
操作符用于比較兩個(gè)對(duì)象的身份,即它們是否是同一個(gè)對(duì)象或是否位于同一個(gè)內(nèi)存地址。a is b
為真,意味著a
和b
指向同一對(duì)象。==:
==
操作符用于比較兩個(gè)對(duì)象的值是否相等。對(duì)于大多數(shù)內(nèi)置類(lèi)型,這意味著它們的內(nèi)容是否相等。
類(lèi)可以通過(guò)定義
__eq__()
方法來(lái)自定義==
的行為。
09?+和join的區(qū)別
使用 + 運(yùn)算符:
當(dāng)使用
+
運(yùn)算符連接字符串時(shí),會(huì)創(chuàng)建一個(gè)新的字符串對(duì)象。如果在循環(huán)中多次使用
+
連接字符串,這會(huì)導(dǎo)致大量的臨時(shí)字符串對(duì)象被創(chuàng)建和丟棄,從而降低性能。
result = str1 + str2 + str3
使用 str.join() 方法:
str.join()
方法是將一個(gè)字符串列表連接成一個(gè)單一的字符串。相比于
+
運(yùn)算符,使用str.join()
在多個(gè)字符串連接時(shí)更為高效,因?yàn)樗淮涡栽谝粋€(gè)操作中創(chuàng)建一個(gè)新的字符串。
result = "".join([str1, str2, str3])
性能對(duì)比:
考慮以下示例,其中我們想要連接大量的小字符串:
# 使用 + 運(yùn)算符
result = ""
for s in list_of_strings:
? ? result += s
# 使用 join 方法
result = "".join(list_of_strings)
在第一個(gè)示例中,每次迭代都會(huì)創(chuàng)建一個(gè)新的字符串對(duì)象。但在第二個(gè)示例中,只會(huì)創(chuàng)建一個(gè)字符串對(duì)象,因此使用 str.join()
方法通常更為高效。
當(dāng)連接大量字符串時(shí),尤其是在循環(huán)中,使用
str.join()
通常是一個(gè)更好的選擇,因?yàn)樗鼮楦咝А?/p>當(dāng)只連接少數(shù)幾個(gè)字符串時(shí),使用
+
運(yùn)算符可能更為直觀。
10?字典和json字符串相互轉(zhuǎn)化方法
字典轉(zhuǎn)為 JSON 字符串:
使用 json.dumps()
方法可以將字典轉(zhuǎn)為 JSON 字符串。
SON 字符串轉(zhuǎn)為字典:
使用 json.loads()
方法可以將 JSON 字符串轉(zhuǎn)為字典。