閱讀406 返回首頁    go Python


為什麼你應該學 Python?

引言

第一次接觸 Python 是在一節編程入門課上。其實,在此之前了解過它,所以在上課之前我對它的語法已經很熟悉了,但在上課之前我沒有用它做過真正的項目。

盡管對它沒有太大興趣,但我認為把它介紹給人們去學習編程還是很好的。我對它不是不喜歡,而是一種“無所謂”的態度。原因很簡單:它裏麵有太多“魔法”。 C 和 Java 這些語言,對底層的行為描述的很清晰,Python 則完全相反。

另外,Python 結構鬆散:寫大型複雜程序時,遇到規則嚴謹的程序結構體(比如每個文件一個公共類),比其他語言(比如 Java )要費些力氣。但是,在這些方麵 Python 給了你很大的自由。

另一件事是嚴格的編碼風格和調試:因為Python 是解釋型語言,查找問題不太容易:如果C 語言有語法錯誤,編譯器會直接停止編譯,但在解釋型語言中,直到執行到問題行,問題才會被發現。

試著在需要整數的時候傳一個字符串?cc 會馬上提醒你,Python 解釋器卻對此一點都不介意(雖然有工具可以發現這個問題,比如 mypy,但我討論的是通用的Python)。我提到的這些問題是解釋型語言的通病,並非 Python 獨有,但這些是我不喜歡它的主要原因。

還有一個煩人的問題是強製縮進。我們老師(很優秀)認為這是好事情,因為“它強製我們形成簡潔的代碼風格”。確實如此,但還是有點煩,當代碼沒有按預期執行時,你分析代碼想要找出 bug,它卻無影無蹤,過了很長時間之後你發現 if 語句那一行有一個多餘的空格。

我曾經和同事聊過 Python,告訴他為什麼我之前對這個語言不感冒,他笑著問我“問什麼不喜歡Python呢?因為它讀起來很像英語?”是的。因為這個語言做了很多底層的工作,有時候會不清楚發生了什麼。舉個讀文件的例子,假設你想一行一行讀取文件內容並打印出來。C 會這麼做:

python 這麼做:

現在,很多人會認為這是 python 的優勢,然而,第一個例子中,幹了什麼一目了然:

獲取一個文件指針

從文件讀取每一行數據到緩存中,打印緩存中的內容

關閉文件流

python 的例子中看不到這些,它是一種 “魔法般的”過程。現在,有人認為這是好事,因為將程序員與底層實現細節隔離(我同意這個說法),但我想知道到底發生了什麼。

有趣的是,我以上提到的缺點,我現在認為都是優點。為了公平起見,我強調,Python 裏邊沒有魔法,如果你多了解一點,你會發現真的沒有,有的隻是語言解釋代碼的方式,從這點來看,我發現它挺有意思的。

如果你也這麼覺得,我建議你深入了解它的工作機製,如果有東西像魔法,就找出來到底發生了什麼,事情就會變得清晰,魔法就變成了便利。

我的認識發生很大的變化,尤其是我決定使用 Python 後,事實上我現在是 Python 的死忠!現在你也許會想我將會在哪裏說服你學 Python 是個好主意,不要擔心,馬上就到。

作為引言的結尾,我想說明,這隻是我對這個語言的個人感受,隻是個人偏好。我沒有試圖以“如果你用 Python,你就不是真正的程序員(實際上,我不這麼認為)”的理由勸說人們學 C。

當有人問我他們的入門語言應該選哪個,我通常建議他們選 Python,基於我上邊提到的“缺點”的原因。我的感覺來源於我的興趣,我曾經在做一些很底層的東西,你能想到,Python 並不適用。

Python 語言精粹

在借用了JavaScript 暢銷書 《JavaScript 語言精粹》作為本節標題後,我們開始討論本文的主題:為什麼你(沒錯,就是你!)應該學 Python。

1.通用腳本語言

這是我使用 Python 的主要原因。我曾經和很多人做過很多項目,不同的人用不同的係統。就我而言,我經常在windows係統和linux係統之間切換。

舉一個實際的例子,有一個項目,我寫了項目的自動測試腳本,結果發現隻有我能用,因為是用 PowerShell 寫的,而我是項目中唯一使用 Windows 的。

當時同事們自然認為 bash 是最好的,我還向他們解釋 PowerShell 遵循一種不同的模式並且有它的強項(例如,它提供了 .NET 框架接口),它是麵向對象的腳本語言,和 bash 完全不一樣。現在我不想討論哪個更好,因為這不是本文的重點。

那麼這個問題怎麼解決呢?嗯……現在,是否有一種腳本語言可以在所有主流平台上運行呢?你猜對了,它就是Python。

除了可以在主流平台上運行,它還是開箱即用的腳本語言。標準庫包含不少實用程序,提供了獨立於係統的常用接口。

舉一個簡潔明了的例子,假設你想獲取文件夾下所有文件的文件名,然後對其進行處理,在UNIX下,你要這麼做:

用 PowerShell 做類似的事情:

An equivalent functionality in Python can be achieved with:

python 這麼做:

現在我認為,Python 除了可以跑在 Linux,MacOSX 和 Windows 上,它也很易讀。上邊例子中的腳本很簡單,在複雜的例子中不同語言的易讀性差異會更明顯。

就像我之前提到的,Python 自帶了許多強大的庫用來取代 shell 腳本,你會發現,最有用的是:

os – 提供係統無關功能,比如文件目錄和文件讀寫。

subprocess – 產生新進程、與輸入輸出流和返回代碼交互。可以用它來啟動係統已安裝的程序,但請記住如果你擔心腳本的可移植性,這不是最好的選擇。

shutil – 提供對文件和文件集合的高級操作。

argparse – 解析命令行參數,構建命令行接口。

好了,假設你 get 到了重點,跨平台和易讀性聽起來挺不錯的,但是你真的喜歡類 UNIX shell 類似的語法怎麼辦?告訴你個好消息,魚和熊掌可以兼得!看看 Plumbum,它是一個 Python 模塊,它的座右銘是“ 再也不寫 shell 腳本”。它模仿了 shell 語法,同時保持了跨平台。

不要完全拋棄 shell 腳本

即使 Python 可以完全取代 shell 腳本,但也不是必須這麼做,因為 Python 腳本天生適合 Unix 命令行理念,你要做的就是讓它們從 sys.stdin (標準輸入)讀數據,向 sys.stdout(標準輸出)寫數據。

舉個例子,假設你有一個文件,每行有一個單詞,你想知道每個單詞在文中出現的次數。這種情況就沒必要全部是用Python,我們可以使用 cat 命令和我們的腳本,稱它為 namecount.py 一起來完成這個任務。

假設有一個文件,名為 names.txt ,內容如下:

現在使用我們的腳本:

Powershell:

期望的輸出如下(順序可能會變化):

namecount.py 源碼:

無序的信息可讀性差,你可能想按單詞出現的次數對其排序,讓我們試試。我們要用管道輸出文件內容供內建命令處理。

按數字降序排序,我們要做的就是 $> cat names.txt | namecount.py | sort -rn 。如果使用PowerShell 應該這樣:$> Get-Content names.txt | python namecount.py | Sort-Object { [int]$_.split()[-1] } -Descending (你可能聽到了 Unixer 的吐槽聲了,PowerShell 怎麼這麼繁瑣)。

這回我們的輸出是確定的,如下所示:

(旁注:如果你用 PowerShell,cat 是 Get-Content 的別名,sort 是 Sort_object 的別名,所以以上命令可以寫成:$> cat names.txt | python namecount.py 和 $> cat names.txt | python namecount.py | sort { [int]$_.split()[-1] } -Descending )

但願我成功說服你 python 是你某些腳本的替代品,你不必完全拋棄 shell 腳本,因為你可以將 Python 融合到你現有的工作流和工具箱中,還可以從它跨平台,更好的可讀性,還有豐富的庫中獲益(後麵會講)。

2.大量優秀的庫

Python 有非常豐富的庫。我的意思是,幾乎任何事都有庫(有趣的是:如果你在你的Python 解釋器中輸入 import antigravity,在瀏覽器中打開 xkdc 漫畫的頁麵,是不是很酷?)。

我不是很推崇堆疊模塊式的編程,但你不必這樣。因為有太多的庫,不表示你都要使用。我也不喜歡堆疊模塊(它有點像 CBSE),我在了解它們之後才使用。

例如,我決定研究馬爾科夫鏈,我想了一個項目:抓取一個藝術家的所有歌詞,建立一個馬爾科夫鏈,然後從其中生成歌曲。這個項目的目的是生成的歌曲應該能反映出藝術家的風格。

所以我到處找相關的東西,搞出了 lyricst 項目(這隻是個樣品,還不成熟,隻是一個測試項目,如我所言,我隻是隨便搞了一下,沒想深入。如果你想玩的話,它包含有命令行界麵和示例的說明文檔)。

我認為,最好的找歌詞的地方是 RAPGenius,因為它很活躍,經常更新。

為了獲取藝術家所有的歌詞,我必須從網站上爬,然後處理 HTML。幸運的是,Python 很適合做網絡爬蟲,它有強大的庫像 BeautifulSoup 可以處理 HTML。

所以我是這麼做的,先使用 BeautifulSoup 從網頁中抽取我需要的信息(就是歌詞)然後用這些信息構建馬爾科夫鏈。

當然我曾經想用正則表達式構建自己的 HTML 解析器,但是這個庫的存在讓我更關注項目的最終目的:把玩馬爾科夫鏈,讓它更有趣,比方說,從文件中讀取些內容出來。

3.用來做滲透測試很強大

如果你在做滲透測試或僅僅是喜歡玩玩,Python 是你的好幫手!由於Python 在所有 Linux 和 MAC OS 機器上都有安裝,還有豐富的庫,完善的語法,還是一門腳本語言,讓它很適合幹這個。

另一個我為什麼決定使用 Python 的原因(除了我之前提到的)是我對安全很感興趣,Python 是用來做滲透測試的完美選擇。

我在第一次進入領域是通過 Scapy(或 Scapy3k ,python3),我印象很深。Scapy 能夠創建、監聽、解析數據包。它的 API 很簡單,文檔也很完善。

你可以很容易的創建不同層的數據(我指的是 OSI 模型)或者捕獲它們對其進行分析或修改。你甚至可以導出 pcap 文件用 Wireshark 打開。

雖然除了抓包還能做很多事情,還有很多其他的庫也可以,但我在這裏不會涉及,因為這不是本文的重點而且要展開講的話需要一篇文章。

有人可能會說,“哦,太棒了,但我感興趣的是 Windows 設備,裏邊不會自帶 Python”。別當心,你可以用 py2exe 把你的腳本編譯成 .exe 文件。文件可能會有點大(取決於你是用的庫的數量),但這不是重點。

如果你很好奇,請參考 list of Python pentesting tools。 文末我還推薦了幾本書。

4.黑客的語言

Python 是可塑性很強的語言。你可以用各種方法改造它。可參見《 altering the way imports work》和《messing with classes before they are created》這兩篇文章。這隻是一些例子。也讓它成為強大的腳本語言(在第一節有說)適合做滲透測試(第三節),因為它給了你很大的自由。

我不想講太多,但我會講述它讓我驚訝的地方。當時,我在做一個網絡爬蟲( Python 很適合幹這個!),我用的其中一個工具是 BeautifulSoup。 這是我用來學習 Python 的項目之一。Beautifulsoup 處理 HTML 的語法清晰直觀,原因是在自定義行為方麵,Python 給了你很大的自由。了解一番 API 後,發現有 “魔法”。和這種情況類似:

上麵的代碼利用第一個字符串參數創建了一個 BeautifulsSoup 實例,第二個參數表示我想使用 Python 自帶的 HTML 解析器(BeautifulSoup 可以搭配多種解析器)。soup.p 返回一個 Tag(bs4.element.Tag) 對象,表示將作為第一個參數。

以上代碼的輸出是:

現在你可能會想,你說的魔法在哪?馬上就來。魔法在於上麵的代碼可以被修改為任何標簽,甚至可以是自定義的。它意味著下麵的代碼也可以正常運行:

The output is the following:

輸出如下:

當我發現這樣也能運行,我的反應是“怎麼回事?”。因為,第一個例子很容易實現,我的意思是最直接的方法是為每一個 HTML 標簽定義一個屬性(實例變量),在解析過程中如果找到了,就賦值給它們。但是這對第二種情況不適用,不可能對所有的字符串定義屬性。

我想知道它是怎麼實現的,所以我打開 BeautifulSoups 源代碼開始尋找。 我沒有發現任何命名為 p 的屬性,這一點也不奇怪,解析函數沒有對其賦值。

穀歌一番後,我找到了答案:魔法方法。什麼是魔法方法,為什麼要叫這個名字?事實上,魔法方法是給你的類賦予魔法的方法。這種方法通常前後有兩條下劃線(例如 __init__()),在Python文檔的 DataModel model section 有對它的說明。

真正讓 BeautifulSoup 擁有這個功能的魔法方法是__getattr__(self, name)(self 在python 中指向實例,和 Java 中的this 類似)。如果去查看文檔,你會發現第一段如下:

如果在屬性常見地方找不到屬性時,比如既不是實例屬性,又沒有在 self 類樹中找到,則調用該方法(object.__getattr__(self, name))。參數 name 就是屬性名這個方法應當返回(計算過的)屬性值或拋出 AttributeError 異常。

當你嚐試訪問一個不存在的屬性,對象的 __getattr__(self,name) 方法會被調用,將返回一個以name 作為名字的屬性的字符串。

舉個例子。假設你有一個 Person 類,擁有 first_name 屬性。我們給使用者訪問和 name 相同屬性的內容的能力。下麵是代碼:

我們在終端運行代碼:

這意味著我們能憑空構造實例屬性,是不是很棒?所以你可以偷偷的讓你的 Dog 除了汪汪叫之外,還會喵喵叫:

你可以在沒有 reflection 的情況下,隨意添加新屬性。object.__dict__ 是(字典)[https://docs.python.org/3.5/library/stdtypes.html#typesmapping] 包含 object 的屬性和它們的值(注意我說的是 object.dict, object 是一個實例,還有一個 class.dict,是類的屬性的字典)。

意思是:

等價於:

兩者輸出是一樣的:

到這裏你會想,是挺好的,但是有什麼用呢?答案很簡單:magical APIs。你有沒有用過一些 Python 庫讓你感覺像魔法?這是讓它們變的有”魔法”的一種情況。雖然一旦你懂了底層發生的事情,就會發現沒有魔法。

如果你還想了解更多,可以查看文檔中的 Description Protocol。

Python 的麵向對象

Python 的麵向對象有點奇怪。例如,類中沒有私有變量和方法。所以你想在類中創建一個實例變量或私有方法,你必須遵守規則:

一個下劃線 (_)表示私有變量和方法。

兩個下劃線(__) 表示的變量和方法,它們的名字會被修改。

舉個例子,假設你有如下類:

轉到解釋器:

如你所見,你可以訪問 _private 變量,但是最後一個例子發生了什麼,它是否意味著有兩個下劃線的變量是真正的私有變量?答案是 NO,它們的名字被改變了,實際上,它被 Python替換成了 _Foo_secret 。如果你想訪問的話,你仍然可以訪問:

然而,PEP8 建議隻在父類中使用雙下劃線來避免屬性名衝突。“PEP”,表示 “Python Enhancement Proposal”,它用來描述 Python 特性或作用。如果你想要添加一個新特性,你可以創建一個 PEP,這樣可以讓整個社區可以看到並討論。你可以在這裏了解更多的 PEPs。

可見,Python 很信任程序員。

我不會再深入講 OO 了,因為它需要單獨一篇文章(甚至是一係列)來講解。

我確實想給你提個醒,Python 的 OO 可不像 Java 語言那麼自然,你需要慢慢適應,但你知道嗎,它隻是做事的方法不同而已。舉個例子,它沒有抽象類,你必須使用裝飾器來實現這個行為。

結語

希望這篇文章,能夠給你一個學習 Python 的理由。這篇文章來自一個為過去說了Python 的壞話而愧疚,如今在到處宣傳 Python 的人。我先申明一點,這隻是個人喜好問題,當有人問我先學哪門語言時,我通常推薦 Python。

如果你還沒決定,那就給它一次機會!用上一兩個小時,多讀些關於它的東西。如果你喜歡從書上學習,我也會幫你,看看《Fluent Python》, 下節還有更多。

書籍推薦

我兌現了諾言,這一節推薦書籍。我會盡量保持簡短一些,隻包含一些我讀過的書籍。

《Fluent Python》 —— 一本講 Python3 的好書。無論你是新手、熟手還是高手都值得一讀。包含了 Python 的來龍去脈。

《Web Scraping With Python》 —— 標題已經說明了一切,講如何用Python 來做網絡爬蟲。你會探索如何爬網上的內容,解析 HTML 等。我覺得這本書對爬蟲領域的新手和熟手很有幫助。即使你之前從沒用過Python,你也可以看懂。它沒有涉及任何高級主題。

《Black Hat Python》 —— 這個有趣!你可以創建反彈 SSH shell,木馬等等!如果你想知道 Python 如何做滲透測試,請一定要讀它。注意它使用的是 Python 2,我有一個倉庫,用的是 Python 3。

《Violent Python: A Cookbook for Hackers, Forensic Analysts, Penetration Testers and Security Engineers》 ——比上麵的主題要多,你會學到如何寫一個常見的用於實戰的滲透測試,取證分析和安全腳本。

最後更新:2017-10-08 22:51:28

  上一篇:go Python 3是未來的趨勢!零基礎必學的語法!會漢語就能學會!
  下一篇:go Python爬取B站,鹹魚的正確 GET 姿勢