爲什麼使用縮進來分組語句?15個爲什麼,幫助你更好的理解Python!

點擊上方Python知識圈,選擇設爲星標

回覆1024獲取Python資料


閱讀文本大概需要 6 分鐘。


01. 爲什麼使用縮進來分組語句?

Guido van Rossum 認爲使用縮進進行分組非常優雅,並且大大提高了普通 Python 程序的清晰度。大多數人在一段時間後就學會並喜歡上這個功能。
由於沒有開始/結束括號,因此解析器感知的分組與人類讀者之間不會存在分歧。偶爾 C 程序員會遇到像這樣的代碼片段:
if (x <= y)        x++;        y--;z++;
如果條件爲真,則只執行 x++ 語句,但縮進會使你認爲情況並非如此。即使是經驗豐富的 C 程序員有時會長時間盯着它,想知道爲什麼即使 x > y , y 也在減少。
因爲沒有開始/結束括號,所以 Python 不太容易發生編碼式衝突。在 C 中,括號可以放到許多不同的位置。如果您習慣於閱讀和編寫使用一種風格的代碼,那麼在閱讀(或被要求編寫)另一種風格時,您至少會感到有些不安。
許多編碼風格將開始/結束括號單獨放在一行上。這使得程序相當長,浪費了寶貴的屏幕空間,使得更難以對程序進行全面的瞭解。理想情況下,函數應該適合一個屏幕(例如,20--30 行)。20 行 Python 可以完成比 20 行 C 更多的工作。這不僅僅是由於缺少開始/結束括號 -- 缺少聲明和高級數據類型也是其中的原因 -- 但縮進基於語法肯定有幫助。

02. 爲什麼簡單的算術運算得到奇怪的結果?

請看下一個問題。


03. 爲什麼浮點計算不準確?

用戶經常對這樣的結果感到驚訝:

>>> 1.2 - 1.00.19999999999999996
並且認爲這是 Python 中的一個 bug。其實不是這樣。這與 Python 關係不大,而與底層平臺如何處理浮點數字關係更大。
CPython 中的 float 類型使用 C 語言的 double 類型進行存儲。float 對象的值是以固定的精度(通常爲 53 位)存儲的二進制浮點數,由於 Python 使用 C 操作,而後者依賴於處理器中的硬件實現來執行浮點運算。這意味着就浮點運算而言,Python 的行爲類似於許多流行的語言,包括 C 和 Java。
許多可以輕鬆地用十進制表示的數字不能用二進制浮點表示。例如,在輸入以下語句後:
>>> x = 1.2
爲 x 存儲的值是與十進制的值 1.2 (非常接近) 的近似值,但不完全等於它。在典型的機器上,實際存儲的值是:
1.0011001100110011001100110011001100110011001100110011 (binary)
它對應於十進制數值:
1.1999999999999999555910790149937383830547332763671875 (decimal)
典型的 53 位精度爲 Python 浮點數提供了 15-16 位小數的精度。
要獲得更完整的解釋,請參閱 Python 教程中的 浮點算術 一章。

04. 爲什麼 Python 字符串是不可變的?

有幾個優點。
一個是性能:知道字符串是不可變的,意味着我們可以在創建時爲它分配空間,並且存儲需求是固定不變的。這也是元組和列表之間區別的原因之一。
另一個優點是,Python 中的字符串被視爲與數字一樣“基本”。任何動作都不會將值 8 更改爲其他值,在 Python 中,任何動作都不會將字符串 "8" 更改爲其他值。

05. 異常有多快?

如果沒有引發異常,則 try/except 塊的效率極高。實際上捕獲異常是昂貴的。在 2.0 之前的 Python 版本中,通常使用這個習慣用法:
try:value = mydict[key]except KeyError:mydict[key] = getvalue(key)value = mydict[key]
只有當你期望 dict 在任何時候都有 key 時,這纔有意義。如果不是這樣的話,你就是應該這樣編碼:
if key in mydict:value = mydict[key]else:value = mydict[key] = getvalue(key)
對於這種特定的情況,您還可以使用 value = dict.setdefault(key, getvalue(key)),但前提是調用 getvalue()足夠便宜,因爲在所有情況下都會對其進行評估。

06. 爲什麼 Python 中沒有 switch 或 case 語句?

你可以通過一系列 if... elif... elif... else.輕鬆完成這項工作。對於 switch 語句語法已經有了一些建議,但尚未就是否以及如何進行範圍測試達成共識。有關完整的詳細信息和當前狀態,請參閱 PEP 275 
對於需要從大量可能性中進行選擇的情況,可以創建一個字典,將 case 值映射到要調用的函數。例如:
def function_1(...): ...
functions = {'a': function_1, 'b': function_2, 'c': self.method_1, ...}
func = functions[value]func()
對於對象調用方法,可以通過使用 getattr() 內置檢索具有特定名稱的方法來進一步簡化:
def visit_a(self, ...): ......
def dispatch(self, value): method_name = 'visit_' + str(value) method = getattr(self, method_name) method()
建議對方法名使用前綴,例如本例中的 visit_ 。如果沒有這樣的前綴,如果值來自不受信任的源,攻擊者將能夠調用對象上的任何方法。

07. 難道不能在解釋器中模擬線程,而非得依賴特定於操作系統的線程實現嗎?

答案 1:不幸的是,解釋器爲每個 Python 堆棧幀推送至少一個 C 堆棧幀。此外,擴展可以隨時回調 Python。因此,一個完整的線程實現需要對 C 的線程支持。
答案 2:幸運的是, Stackless Python 有一個完全重新設計的解釋器循環,可以避免 C 堆棧。

08. 爲什麼 lambda 表達式不包含語句?

Python 的 lambda 表達式不能包含語句,因爲 Python 的語法框架不能處理嵌套在表達式內部的語句。然而,在 Python 中,這並不是一個嚴重的問題。與其他語言中添加功能的 lambda 表單不同,Python 的 lambdas 只是一種速記符號,如果您懶得定義函數的話。
函數已經是 Python 中的第一類對象,可以在本地範圍內聲明。因此,使用 lambda 而不是本地定義的函數的唯一優點是你不需要爲函數創建一個名稱 -- 這只是一個分配了函數對象(與 lambda 表達式生成的對象類型完全相同)的局部變量!

09. 可以將 Python 編譯爲機器代碼,C 或其他語言嗎?

Cython 將帶有可選註釋的 Python 修改版本編譯到 C 擴展中。Nuitka 是一個將 Python 編譯成 C++ 代碼的新興編譯器,旨在支持完整的 Python 語言。要編譯成 Java,可以考慮 VOC 。

10. Python 如何管理內存?

Python 內存管理的細節取決於實現。Python 的標準實現 CPython 使用引用計數來檢測不可訪問的對象,並使用另一種機制來收集引用循環,定期執行循環檢測算法來查找不可訪問的循環並刪除所涉及的對象。gc 模塊提供了執行垃圾回收、獲取調試統計信息和優化收集器參數的函數。
但是,其他實現(如 Jython 或 PyPy ),)可以依賴不同的機制,如完全的垃圾回收器 。如果你的 Python 代碼依賴於引用計數實現的行爲,則這種差異可能會導致一些微妙的移植問題。
在一些 Python 實現中,以下代碼(在 CPython 中工作的很好)可能會耗盡文件描述符:
for file in very_long_list_of_files: f = open(file)c = f.read(1)
實際上,使用 CPython 的引用計數和析構函數方案, 每個新賦值的 f 都會關閉前一個文件。然而,對於傳統的 GC,這些文件對象只能以不同的時間間隔(可能很長的時間間隔)被收集(和關閉)。
如果要編寫可用於任何 python 實現的代碼,則應顯式關閉該文件或使用 with 語句;無論內存管理方案如何,這都有效:
for file in very_long_list_of_files: with open(file) as f:c = f.read(1)


11. 爲什麼 CPython 不使用更傳統的垃圾回收方案?

首先,這不是 C 標準特性,因此不能移植。(是的,我們知道 Boehm GC 庫。它包含了 大多數 常見平臺(但不是所有平臺)的彙編代碼,儘管它基本上是透明的,但也不是完全透明的; 要讓 Python 使用它,需要使用補丁。)
當 Python 嵌入到其他應用程序中時,傳統的 GC 也成爲一個問題。在獨立的 Python 中,可以用 GC 庫提供的版本替換標準的 malloc()和 free(),嵌入 Python 的應用程序可能希望用 它自己 替代 malloc()和 free(),而可能不需要 Python 的。現在,CPython 可以正確地實現 malloc()和 free()。

12. CPython 退出時爲什麼不釋放所有內存?

當 Python 退出時,從全局命名空間或 Python 模塊引用的對象並不總是被釋放。如果存在循環引用,則可能發生這種情況 C 庫分配的某些內存也是不可能釋放的(例如像 Purify 這樣的工具會抱怨這些內容)。但是,Python 在退出時清理內存並嘗試銷燬每個對象。
如果要強制 Python 在釋放時刪除某些內容,請使用 atexit 模塊運行一個函數,強制刪除這些內容。

13. 爲什麼有單獨的元組和列表數據類型?

雖然列表和元組在許多方面是相似的,但它們的使用方式通常是完全不同的。可以認爲元組類似於 Pascal 記錄或 C 結構;它們是相關數據的小集合,可以是不同類型的數據,可以作爲一個組進行操作。例如,笛卡爾座標適當地表示爲兩個或三個數字的元組。
另一方面,列表更像其他語言中的數組。它們傾向於持有不同數量的對象,所有對象都具有相同的類型,並且逐個操作。例如, os.listdir('.') 返回表示當前目錄中的文件的字符串列表。如果向目錄中添加了一兩個文件,對此輸出進行操作的函數通常不會中斷。
元組是不可變的,這意味着一旦創建了元組,就不能用新值替換它的任何元素。列表是可變的,這意味着您始終可以更改列表的元素。只有不變元素可以用作字典的 key,因此只能將元組和非列表用作 key。

14. 列表如何在 CPython 中實現?

CPython 的列表實際上是可變長度的數組,而不是 lisp 風格的鏈表。該實現使用對其他對象的引用的連續數組,並在列表頭結構中保留指向該數組和數組長度的指針。
這使得索引列表 a[i] 的操作成本與列表的大小或索引的值無關。
當添加或插入項時,將調整引用數組的大小。並採用了一些巧妙的方法來提高重複添加項的性能; 當數組必須增長時,會分配一些額外的空間,以便在接下來的幾次中不需要實際調整大小。

15. 字典如何在 CPython 中實現?

CPython 的字典實現爲可調整大小的哈希表。與 B-樹相比,這在大多數情況下爲查找(目前最常見的操作)提供了更好的性能,並且實現更簡單。
字典的工作方式是使用 hash() 內置函數計算字典中存儲的每個鍵的 hash 代碼。hash 代碼根據鍵和每個進程的種子而變化很大;例如,"Python" 的 hash 值爲-539294296,而"python"(一個按位不同的字符串)的 hash 值爲 1142331976。然後,hash 代碼用於計算內部數組中將存儲該值的位置。假設您存儲的鍵都具有不同的 hash 值,這意味着字典需要恆定的時間 -- O(1),用 Big-O 表示法 -- 來檢索一個鍵。
來源:Python官方文檔、中國統計網

留言打卡 DAY 45

今日的留言話題是:你最喜歡Python中的哪個設計?關於留言打卡的規則可以參考 留言打卡送福利 (點擊鏈接查看詳細打卡規則),請按照 暱稱+天數(請以自己實際打卡的天數爲準,如day1 or day2 or day3)+ 留言內容(不少於15字)的方式留言。

Python知識圈公衆號的交流羣已經建立,羣裏可以領取 Python 和人工智能學習資料,大家可以一起學習交流,效率更高,如果是想發推文、廣告、砍價小程序的敬請繞道一定記得備註「交流學習」,我會盡快通過好友申請哦!通過好友後私聊我「學習資料」或者「進羣」都可以。

掃碼添加,備註:交流學習

往期推薦
01

你相信逛B站也能學編程嗎?Python爬蟲B站視頻

02

講講Python爬蟲繞過登錄的小技巧

03

入門 | 32個常用 Python 實現


分享給你的朋友

點個在看

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章