1. 程式人生 > >Python/Java程序員面試必備常用問題解析與答案

Python/Java程序員面試必備常用問題解析與答案

分組 提取 隊列 off 中間人 新的 而不是 生死 轉義

  • 轉自AI算法聯盟,理解python技術問題,以及一些常見的java面試中經常遇到的問題,這些面試問題分為四類:
  • 是什麽(what)

  • 如何做(how)

  • 說區別/談優勢(difference)

  • 實踐操作(practice)

1. 什麽是Python?

Python是一種編程語言,它有對象、模塊、線程、異常處理和自動內存管理。可以加入與其他語言的對比。下面是回答這一問題的幾個關鍵點:

a. Python是一種解釋型語言,python代碼在運行之前不需要編譯。

b. Python是動態類型語言,在聲明變量時,不需要說明變量的類型。

c. Python適合面向對象的編程,因為它支持通過組合與繼承的方式定義類。

d. 在Python語言中,函數是第一類對象。

e. Python代碼編寫快,但是運行速度比編譯語言通常要慢。

f. Python用途廣泛,常被用作“膠水語言”,可幫助其他語言和組件改善運行狀況。

g. 使用Python,程序員可以專註於算法和數據結構的設計,而不用處理底層的細節。

2. 什麽是Python自省?

python自省是python具有的一種能力,使程序員面向對象的語言所寫的程序在運行時,能夠獲得對象的類python型。Python是一種解釋型語言。為程序員提供了極大的靈活性和控制力。

3. 什麽是PEP 8?

PEP8是一種編程規範,內容是一些關於如何讓你的程序更具可讀性的建議。

4. 什麽是pickling和unpickling?

Pickle模塊讀入任何Python對象,將它們轉換成字符串,然後使用dump函數將其轉儲到一個文件中——這個過程叫做pickling。反之從存儲的字符串文件中提取原始Python對象的過程,叫做unpickling。

5. 什麽是Python裝飾器?

Python裝飾器是Python中的特有變動,可以使修改函數變得更容易。

6. 什麽是Python的命名空間?

在Python中,所有的名字都存在於一個空間中,它們在該空間中存在和被操作——這就是命名空間。它就好像一個盒子,每一個變量名字都對應裝著一個對象。當查詢變量的時候,會從該盒子裏面尋找相應的對象。

7. 什麽是字典推導式和列表推導式?

它們是可以輕松創建字典和列表的語法結構。

8. Lambda函數是什麽?

這是一個常被用於代碼中的單個表達式的匿名函數。

9. *args,**kwargs?參數是什麽?

如果我們不確定要往函數中傳入多少個參數,或者我們想往函數中以列表和元組的形式傳參數時,那就使要用*args;如果我們不知道要往函數中傳入多少個關鍵詞參數,或者想傳入字典的值作為關鍵詞參數時,那就要使用**kwargs。

10. 什麽是Pass語句?

Pass是一個在Python中不會被執行的語句。在復雜語句中,如果一個地方需要暫時被留白,它常常被用於占位符。

11. unittest是什麽?

在Python中,unittest是Python中的單元測試框架。它擁有支持共享搭建、自動測試、在測試中暫停代碼、將不同測試叠代成一組,等等的功能。

11. 構造器是什麽?

構造器是實現叠代器的一種機制。它功能的實現依賴於yield表達式,除此之外它跟普通的函數沒有兩樣。

12. doc string是什麽?

Python中文檔字符串被稱為docstring,它在Python中的作用是為函數、模塊和類註釋生成文檔。

13. 負索引是什麽?

Python中的序列索引可以是正也可以是負。如果是正索引,0是序列中的第一個索引,1是第二個索引。如果是負索引,(-1)是最後一個索引而(-2)是倒數第二個索引。

14. 模塊和包是什麽?

在Python中,模塊是搭建程序的一種方式。每一個Python代碼文件都是一個模塊,並可以引用其他的模塊,比如對象和屬性。

一個包含許多Python代碼的文件夾是一個包。一個包可以包含模塊和子文件夾。

15. 垃圾回收是什麽?

在Python中,為了解決內存泄露問題,采用了對象引用計數,並基於引用計數實現自動垃圾回收。

16. CSRF是什麽?

CSRF是偽造客戶端請求的一種攻擊,CSRF的英文全稱是Cross Site Request Forgery,字面上的意思是跨站點偽造請求。

1

HOW

1. 如何讓你的程序更具可讀性?

適當地加入非前導空格,適當的空行以及一致的命名。

2. Python是如何被解釋的?

Python是一種解釋性語言,它的源代碼可以直接運行。Python解釋器會將源代碼轉換成中間語言,之後再翻譯成機器碼再執行。

3. 如何在Python中拷貝一個對象?

如果要在Python中拷貝一個對象,大多時候你可以用copy.copy()或者copy.deepcopy()。但並不是所有的對象都可以被拷貝。

4. 如何用Python刪除一個文件?

使用函數os.remove("file")

5. 如何將一個數字轉換成一個字符串?

你可以使用自帶函數str()將一個數字轉換為字符串。如果你想要八進制或者十六進制數,可以用oct()或hex()。

6. Python是如何進行內存管理的?

Python的內存管理是由私有heap空間管理的。所有的Python對象和數據結構都在一個私有heap中。程序員沒有訪問該heap的權限,只有解釋器才能對它進行操作。為Python的heap空間分配內存是由Python的內存管理模塊進行的,其核心API會提供一些訪問該模塊的方法供程序員使用。Python有自帶的垃圾回收系統,它回收並釋放沒有被使用的內存,讓它們能夠被其他程序使用。

7. 如何實現tuple和list的轉換?

以list作為參數將tuple類初始化,將返回tuple類型

以tuple作為參數將list類初始化,將返回list類型

8. Python裏面如何生成隨機數?

在python中用於生成隨機數的模塊是random,在使用前需要import. 如下例子可以酌情列舉:

random.random():生成一個0-1之間的隨機浮點數

random.uniform(a, b):生成[a,b]之間的浮點數

random.randint(a, b):生成[a,b]之間的整數

random.randrange(a, b, step):在指定的集合[a,b)中,以step為基數隨機取一個數

random.choice(sequence):從特定序列中隨機取一個元素,這裏的序列可以是字符串,列表,元組等

9. 如何在一個function裏面設置一個全局的變量

如果要給全局變量在一個函數裏賦值,必須使用global語句。global VarName的表達式會告訴Python, VarName是一個全局變量,這樣Python就不會在局部命名空間裏尋找這個變量了

10. Python如何實現單例模式?其他23種設計模式python如何實現?

單例模式主要有四種方法:__new__、共享屬性、裝飾器、import。

其他23種設計模式可基本分為創建型、結構型和行為型模式。

創建模式,提供實例化的方法,為適合的狀況提供相應的對象創建方法。

結構化模式,通常用來處理實體之間的關系,使得這些實體能夠更好地協同工作。

行為模式,用於在不同的實體建進行通信,為實體之間的通信提供更容易,更靈活的通信方法。

各模式的實現可根據其特點編寫代碼(限於篇幅,此處不做示例)

11. 如何判斷單向鏈表中是否有環

首先遍歷鏈表,尋找是否有相同地址,借此判斷鏈表中是否有環。如果程序進入死循環,則需要一塊空間來存儲指針,遍歷新指針時將其和儲存的舊指針比對,若有相同指針,則該鏈表有環,否則將這個新指針存下來後繼續往下讀取,直到遇見NULL,這說明這個鏈表無環。

12. 如何遍歷一個內部未知的文件夾?

常用的有以下這幾種辦法:os.path.walk(),os.walk(),listdir

13. mysql數據庫如何分區、分表?

分表可以通過三種方式:mysql集群、自定義規則和merge存儲引擎。

分區有四類:

RANGE 分區:基於屬於一個給定連續區間的列值,把多行分配給分區。

LIST 分區:類似於按RANGE分區,區別在於LIST分區是基於列值匹配一個離散值集合中的某個值來進行選擇。

HASH分區:基於用戶定義的表達式的返回值來進行選擇的分區,該表達式使用將要插入到表中的這些行的列值進行計算。這個函數可以包含MySQL 中有效的、產生非負整數值的任何表達式。

KEY 分區:類似於按HASH分區,區別在於KEY分區只支持計算一列或多列,且MySQL 服務器提供其自身的哈希函數。必須有一列或多列包含整數值。

14. 如何對查詢命令進行優化?

a. 應盡量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索。

b. 應盡量避免在 where 子句中對字段進行 null 值判斷,避免使用!=或<>操作符,避免使用 or 連接條件,或在where子句中使用參數、對字段進行表達式或函數操作,否則會導致權標掃描

c. 不要在 where 子句中的“=”左邊進行函數、算術運算或其他表達式運算,否則系統將可能無法正確使用索引。

d. 使用索引字段作為條件時,如果該索引是復合索引,那麽必須使用到該索引中的第一個字段作為條件時才能保證系統使用該索引,否則該索引將不會被使用。

e. 很多時候可考慮用 exists 代替 in

f. 盡量使用數字型字段

g. 盡可能的使用 varchar/nvarchar 代替 char/nchar

h. 任何地方都不要使用 select * from t ,用具體的字段列表代替“*”,不要返回用不到的任何字段。

i. 盡量使用表變量來代替臨時表。

j. 避免頻繁創建和刪除臨時表,以減少系統表資源的消耗。

k. 盡量避免使用遊標,因為遊標的效率較差。

l. 在所有的存儲過程和觸發器的開始處設置 SET NOCOUNT ON ,在結束時設置 SET NOCOUNT OFF

m. 盡量避免大事務操作,提高系統並發能力。

n. 盡量避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理。

15. 如何理解開源?

開源,即開放源代碼。開源誕生於軟件行業,它不僅僅代表軟件源代碼的開放,本身即意味著自由、共享和充分利用資源。開源是一種精神,是一種文化,如今已經成為軟件業發展的大勢所趨。

16. 如何理解MVC/MTV框架?

MVC就是把Web應用分為模型(M),控制器(C)和視圖(V)三層,他們之間以一種插件式的、松耦合的方式連接在一起。MTV模式本質上和MVC是一樣的,也是為了各組件間保持松耦合關系,只是定義上有些許不同。

17. MSSQL的死鎖是如何產生的?

如下是死鎖產生的四個必要條件:

互斥條件:指進程對所分配到的資源進行排它性使用,即在一段時間內某資源只由一個進程占用。如果此時還有其它進程請求資源,則請求者只能等待,直至占有資源的進程用畢釋放。

請求和保持條件:指進程已經保持至少一個資源,但又提出了新的資源請求,而該資源已被其它進程占有,此時請求進程阻塞,但又對自己已獲得的其它資源保持不放。

不剝奪條件:指進程已獲得的資源,在未使用完之前,不能被剝奪,只能在使用完時由自己釋放。

環路等待條件:指在發生死鎖時,必然存在一個進程——資源的環形鏈,即進程集合{P0,P1,P2,···,Pn}中的P0正在等待一個P1占用的資源;P1正在等待P2占用的資源,……,Pn正在等待已被P0占用的資源。

18. Sql註入是如何產生的,如何防止?

程序開發過程中不註意規範書寫sql語句和對特殊字符進行過濾,導致客戶端可以通過全局變量POST和GET提交一些sql語句正常執行。產生Sql註入。下面是防止辦法:

a. 過濾掉一些常見的數據庫操作關鍵字,或者通過系統函數來進行過濾。

b. 在PHP配置文件中將Register_globals=off;設置為關閉狀態

c. SQL語句書寫的時候盡量不要省略小引號(tab鍵上面那個)和單引號

d. 提高數據庫命名技巧,對於一些重要的字段根據程序的特點命名,取不易被猜到的

e. 對於常用的方法加以封裝,避免直接暴漏SQL語句

f. 開啟PHP安全模式:Safe_mode=on;

g. 打開magic_quotes_gpc來防止SQL註入

h. 控制錯誤信息:關閉錯誤提示信息,將錯誤信息寫到系統日誌。

i. 使用mysqli或pdo預處理。

19. xxs如何預防?

XSS漏洞難以檢測,但是為了WEB安全仍需要盡力避免:

針對反射型和存儲型XSS,需要服務端和前端共同預防,針對用戶輸入的數據做解析和轉義,對於前端開發而言,則是善於使用escape,針對data URI內容做正則判斷,禁止用戶輸入非顯示信息。

對於DOM XSS,由於造成XSS的原因在於用戶的輸入,因此在前端,需要特別註意用戶輸入源,並對可能造成的XSS的操作需要進行字串轉義。

20. 如何生成共享秘鑰? 如何防範中間人攻擊?

密鑰的生成是通過使用全局配置命令完成的:對於不可輸出密鑰是<crypto key generate rsa label {label string},而對於可輸出密鑰則是<crypto key generate rsa exportable label {label string}>。標記(label)是可選擇的;如果沒有指定標記,那麽密鑰名稱將是hostname.domain-name。

對於中間人的攻擊,可以采用如下防範手段:

a. 通過采用動態ARP檢測、DHCP Snooping等控制操作來加強網絡基礎設施

b. 采用傳輸加密

c. 使用CASBs(雲訪問安全代理)

d. 創建RASP(實時應用程序自我保護)

e. 阻止自簽名證書

f. 強制使用SSL pinning

g. 安裝DAM(數據庫活動監控)

21. 如何管理不同版本的代碼?

進行版本管理。可舉例告知如何使用Git(或是其他工具)進行追蹤。

2

Difference

1. 數組和元組之間的區別?

數組在python中叫作列表。列表可以修改,而元組不可以修改,如果元組中僅有一個元素,則要在元素後加上逗號。元組和列表的查詢方式一樣。元組只可讀不可修改,如果程序中的數據不允許修改可用元組。

2. _new_和_init_的區別?

__init__是當實例對象創建完成後被調用的,然後設置對象屬性的一些初始值。

__new__是在實例創建之前被調用的,因為它的任務就是創建實例然後返回該實例,是個靜態方法。

也就是,__new__在__init__之前被調用,__new__的返回值(實例)將傳遞給__init__方法的第一個參數,然後__init__給這個實例設置一些參數。

3. Python中單下劃線和雙下劃綫的區別?

"單下劃線" 開始的成員變量叫做保護變量,意思是只有類對象和子類對象自己能訪問到這些變量;

"雙下劃線" 開始的是私有成員,意思是只有類對象自己能訪問,連子類對象也不能訪問到這個數據。

4. 淺拷貝與深拷貝的區別是?

在python中,對象賦值實際上是對象的引用。淺拷貝,沒有拷貝子對象,所以原始數據改變,子對象會改變,而深拷貝,包含對象裏面的自對象的拷貝,所以原始對象的改變不會造成深拷貝裏任何子元素的改變。

5. 使用裝飾器的單例和使用其他方法的單例,在後續使用中,有何區別?

Import方法改變了類本身,new方法,但是只是把所有實例對象共享屬性,每次產生一個新對象。算作偽單例,共享屬性方法實例化了許多個相同屬性。所以,裝飾器方法最為實用。

6. 多進程與多線程的區別?

a. 簡而言之,一個程序至少有一個進程,一個進程至少有一個線程。

b. 線程的劃分尺度小於進程,使得多線程程序的並發性高。

c. 另外,進程在執行過程中擁有獨立的內存單元,而多個線程共享內存,從而極大地提高了程序的運行效率。

d. 線程在執行過程中與進程還是有區別的。每個獨立的線程有一個程序運行的入口、順序執行序列和程序的出口。但是線程不能夠獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制。

e. 從邏輯角度來看,多線程的意義在於一個應用程序中,有多個執行部分可以同時執行。但操作系統並沒有將多個線程看做多個獨立的應用,來實現進程的調度和管理以及資源分配。這就是進程和線程的重要區別。

7. select和epoll的區別?

a. select實現需要自己不斷輪詢所有fd集合,直到設備就緒,期間可能要睡眠和喚醒多次交替。而epoll其實也需要調用epoll_wait不斷輪詢就緒鏈表,期間也可能多次睡眠和喚醒交替,但是它是設備就緒時,調用回調函數,把就緒fd放入就緒鏈表中,並喚醒在epoll_wait中進入睡眠的進程。雖然都要睡眠和交替,但是select在“醒著”的時候要遍歷整個fd集合,而epoll在“醒著”的時候只要判斷一下就緒鏈表是否為空就行了,這節省了大量的CPU時間。

b. select每次調用都要把fd集合從用戶態往內核態拷貝一次,並且要把current往設備等待隊列中掛一次,而epoll只要一次拷貝,而且把current往等待隊列上掛也只掛一次(在epoll_wait的開始,註意這裏的等待隊列並不是設備等待隊列,只是一個epoll內部定義的等待隊列)。這也能節省不少的開銷。

8. TCP和UDP的區別?邊緣觸發和水平觸發的區別?

a. 基本區別:

  • 基於連接與無連接

  • TCP要求系統資源較多,UDP較少;

  • UDP程序結構較簡單

  • 流模式(TCP)與數據報模式(UDP);

  • TCP保證數據正確性,UDP可能丟包

  • TCP保證數據順序,UDP不保證

b. 編程中的區別

  • socket()的參數不同

  • UDP Server不需要調用listen和accept

  • UDP收發數據用sendto/recvfrom函數

  • TCP:地址信息在connect/accept時確定

  • UDP:在sendto/recvfrom函數中每次均 需指定地址信息

  • UDP:shutdown函數無效

9. HTTP連接:get和post的區別?

GET請求,請求的數據會附加在URL之後,以?分割URL和傳輸數據,多個參數用&連接。URL的編碼格式采用的是ASCII編碼,而不是uniclde,即是說所有的非ASCII字符都要編碼之後再傳輸。

POST請求:POST請求會把請求的數據放置在HTTP請求包的包體中。上面的item=bandsaw就是實際的傳輸數據。

因此,GET請求的數據會暴露在地址欄中,而POST請求則不會。

10. varchar與char的區別?

char 長度是固定的,不管你存儲的數據是多少他都會都固定的長度。而varchar則處可變長度但他要在總長度上加1字符,這個用來存儲位置。所以在處理速度上char要比varchar快速很多,但是對費存儲空間,所以對存儲不大,但在速度上有要求的可以使用char類型,反之可以用varchar類型。

11. BTree索引和hash索引的區別?

Hash 索引因其結構的特殊性,其檢索效率非常高,索引的檢索可以一次定位,不像B-Tree 索引需要從根節點到枝節點,最後才能訪問到頁節點這樣多次的IO訪問,所以 Hash 索引的查詢效率要遠高於 B-Tree 索引。但也有如下明顯的缺點:

a. Hash 索引僅僅能滿足"=","IN"和"<=>"查詢,不能使用範圍查詢。

b. Hash 索引無法被用來避免數據的排序操作。

c. Hash 索引不能利用部分索引鍵查詢。

d. Hash 索引在任何時候都不能避免表掃描。

e. Hash 索引遇到大量Hash值相等的情況後性能並不一定就會比B-Tree索引高。

12. primary key和unique的區別?

a. 作為Primary Key的域/域組不能為null,而Unique Key可以。

b. 在一個表中只能有一個Primary Key,而多個Unique Key可以同時存在。

C. 邏輯設計上講,Primary Key一般在邏輯設計中用作記錄標識,這也是設置Primary Key的本來用意,而Unique Key只是為了保證域/域組的唯一性。

13. ecb和cbc模式有什麽區別?

ECB:是一種基礎的加密方式,密文被分割成分組長度相等的塊(不足補齊),然後單獨一個個加密,一個個輸出組成密文。

CBC:是一種循環模式,前一個分組的密文和當前分組的明文異或操作後再加密,這樣做的目的是增強破解難度。ECB和CBC的加密結果是不一樣的,兩者的模式不同,而且CBC會在第一個密碼塊運算時加入一個初始化向量。

14. 對稱加密與非對稱加密的區別?

對稱加密,需要對加密和解密使用相同密鑰的加密算法。由於其速度快,對稱性加密通常在消息發送方需要加密大量數據時使用。所以,對稱性加密也稱為密鑰加密。

而非對稱加密算法需要兩個密鑰:公開密鑰和私有密鑰。公開密鑰與私有密鑰是一對,如果用公開密鑰對數據進行加密,只有用對應的私有密鑰才能解密;如果用私有密鑰對數據進行加密,那麽只有用對應的公開密鑰才能解密。

15. Xrange和range的區別?

range([start,] stop[, step]),根據start與stop指定的範圍以及step設定的步長,生成一個序列。xrange 用法與 range 完全相同,所不同的是生成的不是一個list對象,而是一個生成器。要生成很大的數字序列的時候,用xrange會比range性能優很多,因為不需要一上來就開辟一塊很大的內存空間。range會直接生成一個list對象,而xrange則不會直接生成一個list,而是每次調用返回其中的一個值。

16. os與sys模塊的區別?

前者提供了一種方便的使用操作系統函數的方法。後者提供訪問由解釋器使用或維護的變量和與解釋器進行交互的函數。

17. NoSQL和關系數據庫的區別?

a. SQL數據存在特定結構的表中;而NoSQL則更加靈活和可擴展,存儲方式可以省是JSON文檔、哈希表或者其他方式。

b. 在SQL中,必須定義好表和字段結構後才能添加數據,例如定義表的主鍵(primary key),索引(index),觸發器(trigger),存儲過程(stored procedure)等。表結構可以在被定義之後更新,但是如果有比較大的結構變更的話就會變得比較復雜。在NoSQL中,數據可以在任何時候任何地方添加,不需要先定義表。

c. SQL中如果需要增加外部關聯數據的話,規範化做法是在原表中增加一個外鍵,關聯外部數據表。而在NoSQL中除了這種規範化的外部數據表做法以外,我們還能用如下的非規範化方式把外部數據直接放到原數據集中,以提高查詢效率。缺點也比較明顯,更新審核人數據的時候將會比較麻煩。

d. SQL中可以使用JOIN表鏈接方式將多個關系數據表中的數據用一條簡單的查詢語句查詢出來。NoSQL暫未提供類似JOIN的查詢方式對多個數據集中的數據做查詢。所以大部分NoSQL使用非規範化的數據存儲方式存儲數據。

e. SQL中不允許刪除已經被使用的外部數據,而NoSQL中則沒有這種強耦合的概念,可以隨時刪除任何數據。

f. SQL中如果多張表數據需要同批次被更新,即如果其中一張表更新失敗的話其他表也不能更新成功。這種場景可以通過事務來控制,可以在所有命令完成後再統一提交事務。而NoSQL中沒有事務這個概念,每一個數據集的操作都是原子級的。

g. 在相同水平的系統設計的前提下,因為NoSQL中省略了JOIN查詢的消耗,故理論上性能上是優於SQL的。

3

Practice

這種實踐操作類題目比較豐富多樣,如下幾類比較常見:

技術分享圖片

1. 補充缺失的代碼

def print_directory_contents(sPath):
import os
for sChild in os.listdir(sPath):
sChildPath = os.path.join(sPath,sChild)
if os.path.isdir(sChildPath):
print_directory_contents(sChildPath)
else:
print sChildPath

2. 下面這段代碼的輸出結果是什麽?請解釋。

例如:

技術分享圖片

list1 = [10, ‘a‘]list2 = [123]list3 = [10, ‘a‘]

新的默認列表只在函數被定義的那一刻創建一次。當extendList被沒有指定特定參數list調用時,這組list的值隨後將被使用。這是因為帶有默認參數的表達式在函數被定義的時候被計算,不是在調用的時候被計算。

3. 下面的代碼能夠運行麽?請解釋?

例如:

技術分享圖片

能夠運行。當key缺失時,執行DefaultDict類,字典的實例將自動實例化這個數列。

4. 將函數按照執行效率高低排序,並證明自己的答案是正確的。

例如:

技術分享圖片

按執行效率從高到低排列:f2、f1和f3。要證明這個答案是正確的,你應該知道如何分析自己代碼的性能。Python中有一個很好的程序分析包,可以滿足這個需求。

技術分享圖片

Python/Java程序員面試必備常用問題解析與答案