如何學習Python,以及新手如何入門?

最近想學Python,在網上找了很多資料,發現很多公開的資料,但是又不清楚具體的從業人員學習python路徑是什麼,想請教一下大家。


蟹妖...

首先當然是買一個遊標卡尺啊,哈哈哈...

而且有了遊標卡尺之後你就不寂寞了,因為遊標卡尺不估讀...

最近據說python還加入了小學課本,這說明 python 是一門小學生都能學會的語言。入門簡單,應用也很廣泛,無論是做後端開發,或者做數據分析一類的工作都很不錯,最近大熱的機器學習也有眾多基於python的框架。如果打算選個語言作為自己的第一門語言,python 可以說是最好的選擇之一了。

無論什麼編程語言,入門學習的方法論都是類似的。

入門學習之前,一定要先有一個目標。比如有些測試同學,想要寫測試腳本,一些做編輯的同學,想要做爬蟲收集數據,對於我來說,主要是為了玩一下TensorFlow,這些是我們想學python的目標。先明確了目標,才知道要達到目標所需要的必要知識和能力有哪些。

好多回答都拉了很長的一個書單,這個對於已經有其他語言基礎的同學來說是挺好的,不過對於入門來說還是有點硬。就好像我們不會為學學英語從頭開始背字典,雖然很多人都嘗試過,當你打開字典的第一頁,看到的第一個單詞就是 abandon。

很多同學,尤其是打算入門的同學依然保留著學校時的思維模式,就是記住100個知識點,考試考100分那種。因為學校的學習其實是一個建立知識網路的過程,這些知識可能很多都不會直接有用,但是當你學習更高級知識的時候,你會發現新知識總能和以前的基礎知識產生聯繫,而所謂理解知識的過程,就是新知識和舊知識建立連接的過程。所以學校里學習知識,之所以要從頭密集的記憶概念,反覆考試,就是為了在腦海里織網,這個網編織的越密集越牢固,以後學習新知識就越容易。而工作中的學習更像是畫一條折線,從已有的基礎出發,達到目標。

所以如果題主是學生,打算學習 python,那麼最簡單的辦法就是把書單裡面的書都從頭到尾讀一遍,至於學完之後能幹什麼,這個不是重點。重點是,是不是記住了,背好了,理解了。

如果是打算有其他目的,比如工作中應用,或者就業的話,那就先明確目標,然後倒推目標的前置知識,直到分解到基礎知識的粒度,然後依次學習。

拿 python 舉例來說,之前我在工作中用過 django(感覺暴露年齡了...),我來假設自己是一個完全不懂 django,也不懂 python 的人。我聽說這是一個 MVC 框架,那我要先搞清楚什麼是 MVC,原來它是包括了路由,數據模型和模板的網站架構,資料庫我也不太懂,那我要知道資料庫如何設置,怎麼來使用它。

接下來,因為這是個 python 的框架,所以我要安裝 python,可能還要使用命令行工具,從前我可沒用過黑屏敲那些高大上的命令,我要學習一下 shell。

至於 python 的基礎部分,如果你學過編程,那你只要找到 python 中使用變數和流程式控制制的方法,以及函數和模塊化的方法,應該就能看懂八成的示例代碼了。

最後你可能還需要知道一點伺服器的知識,至少能夠把網站部署上。

這只是我隨口編的一個場景,你也可以替代成其他的應用,爬蟲也好,商業數據分析也好。出發點一定是你要把 python 當做一種工具,因為你是個工程師,你不是科學家,不是要搞清楚它的運行原理。

好多同學初學的時候,都特別喜歡「鑽研」,凡用框架,必看源碼。這當然沒錯,但你開車上路前難道還要學習怎麼修發動機么?人的精力是有限的,開得穩和開得遠是同樣需要花精力的事情,我們要在保守和功利之間找到一個好的平衡點,而不是一味的保守,覺得攢夠了基礎知識才能出發。

所以從結果倒推是一種很好的方式,它聯結了預期的未來和已知的現在,並且去除了暫時無關的內容。唯一的問題是,在我們對於知識體系一無所知的時候,如何知道我們的結果依賴哪些前置知識?

其實很多問題的答案通過搜索引擎都能夠找到,所謂入門的重點並不是找到每一個問題的答案,而是通過找答案的過程,把這些問題穿起來。一份穿好的問題合集,其實就是教程,只是大多的教程並不是從上自下,而是自下至上,所以可能的問題是,看了很多的教程,依然不知道能做什麼。

所以不妨自己從目標出發制訂一個學習路徑,可以參考各種書籍資料,但是切忌一開始就想要面面俱到,等到達到目標的時候,再回頭充實基礎。

如果沒有那麼多時間精力,或者確實搞不清楚怎麼制定路徑, 倒也可以找一些編排好的課程,不過最好也是有目標導向的,而不是羅列知識點的那種。付費課程的話,優達學城的Python 入門 | Udacity還不錯,門檻很低,從最基礎的講起。他們家的特點是,視頻都是國外的工程師主講的,質量比起國內常見的免費培訓視頻真的是高了不止一個檔次。而且我還蠻喜歡外國工程師講課的方式,感覺比很多國內課程聽起來好理解。

另外就是,這個課和實際項目結合的比較多,算是項目驅動的學習吧。而且是有作業批改和一對一溝通的。

這也是我覺得付費課程中最值得付費的點:在職的工程師和你進行溝通。因為純粹看視頻或者看書,其實價值並不高,知識點本身並不值錢。有價值的是有組織的知識體系,以及能夠幫你解決問題的人。一個月薪2W的工程師,摺合成時薪大概是125,外包的話可能還要翻倍。所以找一個一線大廠的在職工程師陪你聊一下午,你都得承認,這值1000塊,儘管可能你只要請他吃頓飯就好。


書籍列表:(列了下看過和沒看過的一些書的看法)

基本了解:

&<&&>

(Python簡明教程簡明 Python 教程)

網上有資源,兩小時了解基本

如果有其他語言功底,不需要那麼久

入門:

&<&&>

官方入門,英文好的可以通讀一遍,不過貌似也有中文的

&<&&>

我看到的第一本python書,大學圖書館借的,很基礎,但感覺不夠詳細

作簡單入門還是可以的

&<&&>(深入淺出Python)

買的影印版,沒有程序基礎的可以看看,有程序基礎的可以當做英文閱讀訓練…..

&<&&>(Python學習手冊)

有Python3k的內容,內容很全面,很詳細,就是有點厚,啃了一段時間才搞完,我讀的第二本

&<&&>(Pyton核心編程)

python2.x,社區翻譯的,章節理得思路很清晰,比較符合中國人梳理知識的風格。2天翻完了,和上面那本內容基本相似。二選一

&<&<可愛的Python&>&>

沒買,ibm dev裡面有網路版,翻看了一些自己需要的文章

&<&

沒看,沒有發言權…..

進階 再深入:

&<&&>

很基礎,也很不基礎,應該算是入門後想再進一步要看的

&<&&>

買了,還沒翻

&<&&>

沒買,沒發言權,目前工作中沒用到

打算買

&<&&>

正在看,對想更深入了解很有幫助,對寫出更好的代碼也很有幫助

其他:

&<&&>

買了,挑看了部分章節,如果經常在*nix下工作的童鞋,常常寫腳本的同學,建議看看

&<&&>

沒買,沒看,沒發言權

&<&<集體智慧編程&>&>

正在看,主要是機器學習一些基本演算法的介紹,代碼是python寫的,很贊

&<&&>

沒買,沒看,沒發言權

&<&&>

遷移一個項目(Mezzanine
- 一個基於Django1.4的CMS開源項目)到sae時讀完了所有章節,不過不深入。

網上有翻譯版本的

&<&&>

買了,看完了,和上一本重複太多,二選一,建議網上看上面那本

大部頭偶爾查詢

&<&&>

實體中文版貌似剛出,很厚一本,一百來大洋,還沒下手。有電子版,偶爾查查東西用,不過貌似不大完整。

打算手裡這些書過完了再入手

&<&&>

python2.4的,很多奇淫巧計,可以買一本

2.學習路線(針對以上書籍,可以自我調整和評估下,以下只代表個人觀點)

  1. #/usr/bin/env python
  2. #-*- coding=utf-8 -*-
  3. #@author: 林達漫@http://yeah.net
  4. #@version: 0.1
  5. #@date: 2015-02-7
  6. #@desc: python學習線路
  7. step
  8. def read(book=&<&&>) # 網上先過一遍
  9. if 沒興趣:
  10. return
  11. else:
  12. if 沒編程基礎:
  13. &<&&>
  14. if need py2.x:
  15. &<&&>
  16. elif py2.x and py3k:
  17. &<&&>
  18. if you want: #可選
  19. &<&&>
  20. if you have more time and energy:
  21. &<&<可愛的Python&>&>
  22. &<&&>
  23. print "Info: 基本入門了"
  24. if you want go farther:
  25. if True:#強烈建議
  26. &<&&>
  27. &<&&>
  28. &<&&> #這個,沒讀過,自己判定吧
  29. if 工作需要:
  30. &<&&> #網路編程
  31. &<&&> #系統管理相關
  32. &<&&> #web,用到django框架的
  33. &<&&> #同上
  34. &<&<集體智慧編程&>&> #演算法工程師,or 個人愛好
  35. &<&&>
  36. if you want to search for something useful:
  37. &<&&>
  38. &<&&>

3.選用IDE:

這個,自己感覺用得順手就行,關於這個,不詳細介紹,網上自個搜

曬下我用的

windows下: 實驗:IDLE 工程:Eclipse+pydev (目前轉用sublime text2了,有興趣的可以試試)

Linux下: 實驗: Ipython 工程: vim

4.學習方法:

感覺入門無他: 看書+敲代碼實驗

買書的話,基本就行,貌似lz買多了,有部分感覺其實重複了

進階,個人認為: 思考+不停寫代碼重構

菜鳥階段,繼續敲代碼中

5.關於這堆筆記

目標:python基本入門及進階

基於版本: py2.7

參考書籍: 上面那堆書籍 + 網路的一些博文

整理頻率:不定期哈,這個沒法保證,1是比較懶,2是工作比較忙(好吧,這都是借口&>&<)

聲明:


1.本人系菜鳥一枚,這些權做分享,水平有限,錯誤難免,歡迎指正


2.文中引用會盡量註明,由於太雜,遺漏的希望指出,會註明.


3.轉載註明出處哈,謝絕一切商業用途


Life is short, you need Python

人生苦短,我用Python

— Bruce Eckel

5.1 Python簡介

本章將介紹Python的最基本語法,以及一些和深度學習還有計算機視覺最相關的基本使用。

5.1.1 Python簡史

Python是一門解釋型的高級編程語言,特點是簡單明確。Python作者是荷蘭人Guido van Rossum,1982年他獲得數學和計算機碩士學位後,在荷蘭數學與計算科學研究所( C entrum W iskunde I nformatica, CWI )謀了份差事。在CWI期間,Guido參與到了一門叫做ABC的語言開發工作中。ABC是一門教學語言,所以擁有簡單,可讀性好,語法更接近自然語言等特點。在那個C語言一統天下的年代,ABC就是一股簡單的清流,畢竟是門教學語言,最後沒有流行起來,不過這段經歷影響了Guido。1989年的聖誕假期,閑得蛋疼的Guido決定設計一門簡單易用的新語言,要介於C和Shell之間,同時吸取ABC語法中的優點。Guido用自己喜歡的一部喜劇電視劇來命名這門語言:《Monty Python 『s Flying Circus》。

1991年,第一版基於C實現的Python編譯器誕生,因為簡單,拓展性好,Python很快就在Guido的同事中大受歡迎,不久Python的核心開發人員就從Guido一人變成了一個小團隊。後來隨著互聯網時代的到來,開源及社區合作的方式蓬勃發展,Python也藉此上了發展的快車道。因為Python非常容易拓展,在不同領域的開發者貢獻下,許多受歡迎的功能和特徵被開發出來,漸漸形成了各種各樣的庫,其中一部分被加入到Python的標準庫中,這讓本來就不需要過多思考底層細節的Python變得更加強大好用。在不過多考慮執行效率的前提下,使用Python進行開發的周期相比傳統的C/C++甚至Java等語言都大大縮短,代碼量也大幅降低,所以出bug的可能性也小了很多。因此有了語言專家Bruce Eckel的那句名言:Life is short, you need Python. 後來這句話的中文版「人生苦短,我用Python」被Guido印在了T恤上。發展至今,Python漸漸成了最流行的語言之一,在編程語言排行榜TOBIE中常年佔據前5的位置。另外隨著Python的用戶群越來越壯大,慢慢在本身特點上發展出了自己的哲學,叫做Python的禪(The Zen of Python)。遵循Python哲學的做法叫做很Python(Pythonic),具體參見:

PEP 20 — The Zen of Python

或者在Python中執行:

&>&> import this

Python擁有很好的擴充性,可以非常輕鬆地用其他語言編寫模塊供調用,用Python編寫的模塊也可以通過各種方式輕鬆被其他語言調用。所以一種常見的Python使用方式是,底層複雜且對效率要求高的模塊用C/C++等語言實現,頂層調用的API用Python封裝,這樣可以通過簡單的語法實現頂層邏輯,故而Python又被稱為「膠水語言」。這種特性的好處是,無需花費很多時間在編程實現上,更多的時間可以專註于思考問題的邏輯。尤其是對做演算法和深度學習的從業人員,這種方式是非常理想的,所以如今的深度學習框架中,除了MATLAB,或是Deeplearning4j這種擺明了給Java用的,其他框架基本上要麼官方介面就是Python,要麼支持Python介面。

5.1.2 安裝和使用Python

Python有兩個大版本,考慮到用戶群數量和庫的各種框架的兼容性,本文以Python2(2.7)為準,語法盡量考慮和Python3的兼容。

Unix/Linux下的Python基本都是系統自帶的,一般默認為Python2,使用時在終端直接鍵入python就能進入Python解釋器界面:

在解釋器下就已經可以進行最基本的編程了,比如:

寫程序的話還是需要保存成文件再執行,比如我們寫下面語句,並且保存為helloworld.py:

print ( 「Hello world!」 )

然後在終端里執行:

安裝更多的python庫一般有兩種方法,第一是用系統的軟體包管理,以Ubuntu 16.04 LTS為例,比如想要安裝numpy庫(後面會介紹這個庫),軟體包的名字就是python-numpy,所以在終端中輸入:

&>&> sudo apt install python-numpy

Python自己也帶了包管理器,叫做pip,使用如下:

&>&> pip install numpy

安裝和深度學習相關的框架時,一般來說推薦使用系統自帶的包管理,出現版本錯誤的可能性低一些。另外也可以使用一些提前配置好很多第三方庫的Python包,這些包通常已經包含了深度學習框架中絕大多數的依賴庫,比如最常用的是Anaconda:

Download Anaconda Now!

Windows下的Python安裝簡單一些,從官方網站下載相應的安裝程序就可以了,當然也有更方便的已經包含了很全的第三方庫的選擇,WinPython:

WinPython

並且是綠色的,直接執行就可以用了。

5.2 Python基本語法

There should be one– and preferably only one –obvious way to do it.

對於一個特定的問題,應該只用最好的一種方法來解決。

— Tim Peters

5.2.1 基本數據類型和運算

基本數據類型

Python中最基本的數據類型包括整型,浮點數,布爾值和字元串。類型是不需要聲明的,比如:

a = 1 # 整數
b = 1.2 # 浮點數
c = True # 布爾類型
d = "False" # 字元串
e = None # NoneType

其中#是行內注釋的意思。最後一個None是NoneType,注意不是0,在Python中利用type函數可以查看一個變數的類型:

type(a) # &
type(b) # &
type(c) # &
type(d) # &
type(e) # &

注釋中是執行type()函數後的輸出結果,可以看到None是單獨的一種類型NoneType。在很多API中,如果執行失敗就會返回None。

變數和引用

Python中基本變數的賦值一般建立的是個引用,比如下面的語句:

a = 1
b = a
c = 1

a賦值為1後,b=a執行時並不會將a的值複製一遍,然後賦給b,而是簡單地為a所指的值,也就是1建立了一個引用,相當於a和b都是指向包含1這個值的這塊內存的指針。所以c=1執行的也是個引用建立,這三個變數其實是三個引用,指向同一個值。這個邏輯雖然簡單,不過也還是常常容易弄混,這沒關係,Python內置了id函數,可以返回一個對象的地址,用id函數可以讓我們知道每個變數指向的是不是同一個值:

id(a) # 35556792L
id(b) # 35556792L
id(c) # 35556792L

注釋中表示的仍是執行後的結果。如果這時候我們接下面兩個語句:

b = 2 # b的引用到新的一個變數上
id(b) # 35556768L

可以看到b引用到了另一個變數上。

運算符

Python中的數值的基本運算和C差不多,字元串的運算更方便,下面是常見的例子:

a = 2
b = 2.3
c = 3
a + b # 2 + 2.3 = 4.3
c – a # 3 - 2 = 1
a / b # 整數除以浮點數,運算以浮點數為準,2 / 2.3 = 0.8695652173913044
a / c # Python2中,整數除法,向下取整 2 / 3 = 0
a ** c # a的c次方,結果為8
a += 1 # Python中沒有i++的用法,自增用+=
c -= 3 # c變成0了
d = "Hello"
d + " world!" # 相當於字元串拼接,結果為"Hello world!"
d += " "world"!"# 相當於把字元串接在當前字元串尾,d變為"Hello "world"!"
e = r"
\"
print(e) # "\n\t\\"

需要提一下的幾點:1)字元串用雙引號和單引號都可以,區別主要是單引號字元串中如果出現單引號字元則需要用轉義符,雙引號也是一樣,所以在單引號字元串中使用雙引號,或者雙引號字元串中使用單引號就會比較方便。另外三個雙引號或者三個單引號圍起來的也是字元串,因為換行方便,更多用於文檔。2)Python2中兩個數值相除會根據數值類型判斷是否整數除法,Python3種則都按照浮點數。想要在Python2種也執行Python3中的除法只要執行下面語句:

from __future__ import division # 使用Python3中的除法
1 / 2

3)字元串前加r表示字元串內容嚴格按照輸入的樣子,好處是不用轉義符了,非常方便。

Python中的布爾值和邏輯的運算非常直接,下面是例子:

a = True
b = False
a and b # False
a or b # True
not a # False

基本上就是英語,操作符優先順序之類的和其他語言類似。Python中也有位操作:

~8 # 按位翻轉,1000 --&> -(1000+1)
8 &>&> 3 # 右移3位,1000 --&> 0001
1 &<&< 3 # 左移3位,0001 --&> 1000
5 2 # 按位與,101 010 = 000
5 | 2 # 按位或,101 | 010 = 111
4 ^ 1 # 按位異或,100 ^ 001 = 101

==, != 和is

判斷是否相等或者不等的語法和C也一樣,另外在Python中也常常見到is操作符,這兩者的區別在於==和!=比較引用指向的內存中的內容,而is判斷兩個變數是否指向一個地址,看下面的代碼例子:

a = 1
b = 1.0
c = 1
a == b # True,值相等
a is b # False,指向的不是一個對象,這個語句等效於 id(a) == id(b)
a is c # True,指向的都是整型值1

所以一定要分清要比較的對象應該用那種方式,對於一些特殊的情況,比如None,本著Pythonic的原則,最好用is None。

注意關鍵字

Python中,萬物皆對象。不過這並不是這裡要探討的話題,想說的是一定要注意關鍵字,因為所有東西都是對象,所以一個簡簡單單的賦值操作就可以把系統內置的函數給變成一個普通變數,來看下邊例子:

id(type) # 506070640L
type = 1 # type成了指向1的變數
id(type) # 35556792L
id = 2 # id成了指向2的變數
from __future__ import print_function
print = 3 # print成了指向3的變數

注意print是個很特殊的存在,在Python3中是按照函數用,在Python2中卻是個命令式的語句,最早print的用法其實是下邊這樣:

print "Hello world!"

這麼用主要是受到ABC語法的影響,但這個用法並不Pythonic,後來加入了print函數,為了兼容允許兩種用法並存。所以單純給print賦值是不靈的,在Python2中使用Python3中的一些特性都是用from __future__ import來實現。

模塊導入

因為提到了對象名覆蓋和import,所以簡單講一下。import是利用Python中各種強大庫的基礎,比如要計算cos(π)的值,可以有下面4種方式:

# 直接導入Python的內置基礎數學庫
import math
print(math.cos(math.pi))

# 從math中導入cos函數和pi變數
from math import cos, pi
print(cos(pi))

# 如果是個模塊,在導入的時候可以起個別名,避免名字衝突或是方便懶得打字的人使用
import math as m
print(m.cos(m.pi))

# 從math中導入所有東西
from math import *
print(cos(pi))

一般來說最後一種方式不是很推薦,因為不知道import導入的名字里是否和現有對象名已經有衝突,很可能會不知不覺覆蓋了現有的對象。

5.2.2 容器

列表

Python中的容器是異常好用且異常有用的結構。這節主要介紹列表(list),元組(tuple),字典(dict)和集合(set)。這些結構和其他語言中的類似結構並無本質不同,來看例子了解下使用:

a = [1, 2, 3, 4]
b = [1]
c = [1]
d = b
e = [1, "Hello world!", c, False]
print(id(b), id(c)) # (194100040L, 194100552L)
print(id(b), id(d)) # (194100040L, 194100040L)
print(b == c) # True
f = list("abcd")
print(f) # ["a", "b", "c", "d"]
g = [0]*3 + [1]*4 + [2]*2 # [0, 0, 0, 1, 1, 1, 1, 2, 2]

因為變數其實是個引用,所以對列表而言也沒什麼不同,所以列表對類型沒什麼限制。也正因為如此,和變數不同的是,即使用相同的語句賦值,列表的地址也是不同的,在這個例子中體現在id(b)和id(c)不相等,而內容相等。列表也可以用list()初始化,輸入參數需要是一個可以遍歷的結構,其中每一個元素會作為列表的一項。「*」操作符對於列表而言是複製,最後一個語句用這種辦法生成了分段的列表。

列表的基本操作有訪問,增加,刪除,和拼接:

a.pop() # 把最後一個值4從列表中移除並作為pop的返回值
a.append(5) # 末尾插入值,[1, 2, 3, 5]
a.index(2) # 找到第一個2所在的位置,也就是1
a[2] # 取下標,也就是位置在2的值,也就是第三個值3
a += [4, 3, 2] # 拼接,[1, 2, 3, 5, 4, 3, 2]
a.insert(1, 0) # 在下標為1處插入元素0,[1, 0, 2, 3, 5, 4, 3, 2]
a.remove(2) # 移除第一個2,[1, 0, 3, 5, 4, 3, 2]
a.reverse() # 倒序,a變為[2, 3, 4, 5, 3, 0, 1]
a[3] = 9 # 指定下標處賦值,[2, 3, 4, 9, 3, 0, 1]
b = a[2:5] # 取下標2開始到5之前的子序列,[4, 9, 3]
c = a[2:-2] # 下標也可以倒著數,方便算不過來的人,[4, 9, 3]
d = a[2:] # 取下標2開始到結尾的子序列,[4, 9, 3, 0, 1]
e = a[:5] # 取開始到下標5之前的子序列,[2, 3, 4, 9, 3]
f = a[:] # 取從開頭到最後的整個子序列,相當於值拷貝,[2, 3, 4, 9, 3, 0, 1]
a[2:-2] = [1, 2, 3] # 賦值也可以按照一段來,[2, 3, 1, 2, 3, 0, 1]
g = a[::-1] # 也是倒序,通過slicing實現並賦值,效率略低於reverse()
a.sort()
print(a) # 列表內排序,a變為[0, 1, 1, 2, 2, 3, 3]

因為列表是有順序的,所以和順序相關的操作是列表中最常見的,首先我們來打亂一個列表的順序,然後再對這個列表排序:

import random
a = range(10) # 生成一個列表,從0開始+1遞增到9
print(a) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
random.shuffle(a) # shuffle函數可以對可遍歷且可變結構打亂順序
print(a) # [4, 3, 8, 9, 0, 6, 2, 7, 5, 1]
b = sorted(a)
print(b) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
c = sorted(a, reverse=True)
print(c) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

元組

元組和列表有很多相似的地方,最大的區別在於不可變,還有如果初始化只包含一個元素的tuple和列表不一樣,因為語法必須明確,所以必須在元素後加上逗號。另外直接用逗號分隔多個元素賦值默認是個tuple,這在函數多返回值的時候很好用:

a = (1, 2)
b = tuple(["3", 4]) # 也可以從列表初始化
c = (5,)
print(c) # (5,)
d = (6)
print(d) # 6
e = 3, 4, 5
print(e) # (3, 4, 5)

集合

集合是一種很有用的數學操作,比如列表去重,或是理清兩組數據之間的關係,集合的操作符和位操作符有交集,注意不要弄混:

A = set([1, 2, 3, 4])
B = {3, 4, 5, 6}
C = set([1, 1, 2, 2, 2, 3, 3, 3, 3])
print(C) # 集合的去重效果,set([1, 2, 3])
print(A | B) # 求並集,set([1, 2, 3, 4, 5, 6])
print(A B) # 求交集,set([3, 4])
print(A - B) # 求差集,屬於A但不屬於B的,set([1, 2])
print(B - A) # 求差集,屬於B但不屬於A的,set([5, 6])
print(A ^ B) # 求對稱差集,相當於(A-B)|(B-A),set([1, 2, 5, 6])

字典

字典是一種非常常見的「鍵-值」( k ey- v alue)映射結構,鍵無重複,一個鍵不能對應多個值,不過多個鍵可以指向一個值。還是通過例子來了解,構建一個名字-&>年齡的字典,並執行一些常見操作:

a = {"Tom": 8, "Jerry": 7}
print(a["Tom"]) # 8
b = dict(Tom=8, Jerry=7) # 一種字元串作為鍵更方便的初始化方式
print(b["Tom"]) # 8
if "Jerry" in a: # 判斷"Jerry"是否在keys裡面
print(a["Jerry"]) # 7
print(a.get("Spike")) # None,通過get獲得值,即使鍵不存在也不會報異常
a["Spike"] = 10
a["Tyke"] = 3
a.update({"Tuffy": 2, "Mammy Two Shoes": 42})
print(a.values()) # dict_values([8, 2, 3, 7, 10, 42])
print(a.pop("Mammy Two Shoes")) # 移除"Mammy Two Shoes"的鍵值對,並返回42
print(a.keys()) # dict_keys(["Tom", "Tuffy", "Tyke", "Jerry", "Spike"])

注意到初始化字典和集合很像,的確如此,集合就像是沒有值只有鍵的字典。既然有了人名到年齡的映射,也許你立馬想到是否可以給字典排序?在Python3.6之前,這個問題是錯誤的,字典是一種映射關係,沒有順序。當然了,如果要把(鍵, 值)的這種對進行排序,是沒有問題的,前提是先把字典轉化成可排序的結構,items()或者iteritems()可以做到這件事,接上段代碼繼續:

b = a.items()
print(b) # [("Tuffy", 2), ("Spike", 10), ("Tom", 8), ("Tyke", 3), ("Jerry", 7)]
from operator import itemgetter
c = sorted(a.items(), key=itemgetter(1))
print(c) # [("Tuffy", 2), ("Tyke", 3), ("Jerry", 7), ("Tom", 8), ("Spike", 10)]
d = sorted(a.iteritems(), key=itemgetter(1))
print(d) # [("Tuffy", 2), ("Tyke", 3), ("Jerry", 7), ("Tom", 8), ("Spike", 10)]
e = sorted(a)
print(e) # 只對鍵排序,["Jerry", "Spike", "Tom", "Tuffy", "Tyke"]

items()可以把字典中的鍵值對轉化成一個列表,其中每個元素是一個tuple,tuple的第一個元素是鍵,第二個元素是值。變數c是按照值排序,所以需要一個操作符itemgetter,去位置為1的元素作為排序參考,如果直接對字典排序,則其實相當於只是對鍵排序。字典被當作一個普通的可遍歷結構使用時,都相當於遍歷字典的鍵。如果覺得字典沒有順序不方便,可以考慮使用OrderedDict,使用方式如下:

from collections import OrderedDict
a = {1: 2, 3: 4, 5: 6, 7: 8, 9: 10}
b = OrderedDict({1: 2, 3: 4, 5: 6, 7: 8, 9: 10})
print(a) # {1: 2, 3: 4, 9: 10, 5: 6, 7: 8}
print(b) # OrderedDict([(1, 2), (3, 4), (9, 10), (5, 6), (7, 8)])

這樣初始化時的順序就保留了,除了有序的特性以外,用法上和字典沒有區別。2016年9月,Guido宣布在Python3.6中,字典將默認有序,這樣就不用糾結了。另外需要注意的一點是字典是通過哈希表實現的,所以鍵必須是可哈希的, list不能被哈希,所以也不能作為字典的鍵,而tuple就可以。

因為上上段代碼中用到了iteritems(),所以這裡順帶提一下迭代器(iterator),迭代器相當於一個函數,每次調用都返回下一個元素,從遍歷的角度來看就和列表沒有區別了。iteritems()就是一個迭代器,所以效果一樣,區別是迭代器佔用更少內存,因為不需要一上來就生成整個列表。一般來說,如果只需要遍歷一次,用迭代器是更好的選擇,若是要多次頻繁從一個可遍歷結構中取值,且內存夠,則直接生成整個列表會更好。當然,用迭代器生成一個完整列表並不麻煩,所以有個趨勢是把迭代器作為默認的可遍歷方式,比如前面我們使用過用來生成等差數列列表的range(),在Python2中對應的迭代器形式是xrange()。在Python3中,range()就不再產生一個列表了,而是作為迭代器,xrange()直接沒了。

5.2.3 分支和循環

從這節開始,代碼就未必適合在Python終端中輸入了,選個順手的編輯器或者IDE。作者良心推薦PyCharm,雖然慢,但好用,社區版免費:

PyCharm

for循環

上面提到的4種容器類型都是可遍歷的,所以該講講用來遍歷的for循環了。for循環的語法也是簡單的英語:

a = ["This", "is", "a", "list", "!"]
b = ["This", "is", "a", "tuple", "!"]
c = {"This": "is", "an": "unordered", "dict": "!"}

# 依次輸出:"This", "is", "a", "list", "!"
for x in a:
print(x)

# 依次輸出:"This", "is", "a", "tuple", "!"
for x in b:
print(x)

# 鍵的遍歷。不依次輸出:"This", "dict", "an"
for keyin c:
print(key)

# 依次輸出0到9
for i in range(10):
print(i)

注意到每個for循環中,print都有縮進,這是Python中一個讓人愛恨交織的特點: 強行縮進 來表明成塊的代碼。這樣做的好處是代碼十分清晰工整,還有助於防止寫出過長的函數或者過深的嵌套,壞處是有時候不知為什麼tab和空格就一起出現了,又或是多重if-else不知怎得就沒對齊,還是挺麻煩的。

回到for循環上,這種把每個元素拿出來的遍歷方式叫做for_each風格,熟悉Java的話就不會陌生,C++11中也開始支持這種for循環方式。不過如果還是需要下標呢?比如遍歷一個list的時候,希望把對應下標也列印出來,這時可以用enumerate:

names = ["Rick", "Daryl", "Glenn"]

# 依次輸出下標和名字
for i, namein enumerate(names):
print(i, name)

需要注意的是,通過取下標遍歷當然是可行的,比如用len()函數獲得列表長度,然後用range()/xrange()函數獲得下標,但是並不推薦這樣做:

words = ["This", "is", "not", "recommended"]

# not pythonic :(
for i in xrange(len(words)):
print(words[i])

在使用for循環時,有時會遇到這樣一種場景:我們需要對遍歷的每個元素進行某種判斷,如果符合這種判斷的情況沒有發生,則執行一個操作。舉個例子某神秘部門要審核一個字元串列表,如果沒有發現不和諧的字眼,則將內容放心通過,一種解決辦法是下面這樣:

wusuowei = ["I", "don"t", "give", "a", "shit"] # 無所謂

hexie = True # 默認和諧社會
for x in wusuowei:
if x == "f**k":
print("What the f**k!") # 發現了不該出現的東西,WTF!
hexie = False # 不和諧了
break # 趕緊停下!不能再唱了

if hexie: # 未發現不和諧元素!
print("Harmonious society!") # 和諧社會!

這樣需要設置一個標記是否發現不和諧因素的狀態變數hexie,循環結束後再根據這個變數判斷內容是否可以放心通過。一種更簡潔不過有些小眾的做法是直接和else一起,如果for循環中的if塊內的語句沒有被觸發,則通過else執行指定操作:

wusuowei = ["I", "don"t", "give", "a", "shit"]

for x in wusuowei:
if x == "f**k":
print("What the f**k!")
hexie = False
break
else: # for循環中if內語句未被觸發
print("Harmonious society!") # 和諧社會!

這樣不需要一個標記是否和諧的狀態變數,語句簡潔了很多。

if 和分支結構

上一個例子中已經出現if語句了,所以這部分講講if。Python的條件控制主要是三個關鍵字:if-elif-else,其中elif就是else if的意思。還是看例子:

pets =["dog", "cat", "droid", "fly"]

for petin pets:
if pet == "dog": # 狗糧
food = "steak" # 牛排
elif pet == "cat": # 貓糧
food = "milk" # 牛奶
elif pet == "droid": # 機器人
food = "oil" # 機油
elif pet == "fly": # 蒼蠅
food = "sh*t" #
else:
pass
print(food)

需要提一下的是pass,這就是個空語句,什麼也不做,佔位用。Python並沒有switch-case的語法,等效的用法要麼是像上面一樣用if-elif-else的組合,要麼可以考慮字典:

pets = ["dog", "cat", "droid", "fly"]
food_for_pet = {
"dog": "steak",
"cat": "milk",
"droid": "oil",
"fly": "sh*t"
}

for petin pets:
food = food_for_pet[pet] if petin food_for_petelse None
print(food)

這裡還用到了一個if-else常見的行內應用,就是代替三元操作符,如果鍵在字典中,則food取字典的對應值,否則為None。

if 表達式中的小技巧

通過鏈式比較讓語句簡潔:

if -1 &< x &< 1: # 相較於 if x &> -1 and x &< 1: print("The absolute value of x is &< 1")

判斷一個值是不是等於多個可能性中的一個:

if x in ["piano", "violin", "drum"]: # 相較於 if x == "piano" or x == "violin" or x =="drum":
print("It"s an instrument!")

Python中的對象都會關聯一個真值,所以在if表達式中判斷是否為False或者是否為空的時候,是無需寫出明確的表達式的:

a = True
if a: # 判斷是否為真,相較於 a is True
print("a is True")

if "sky": # 判斷是否空字元串,相較於 len("sky") &> 0
print("birds")

if "": # 判斷是否空字元串,同上
print("Nothing!")

if {}: # 判斷是否空的容器(字典),相較於len({}) &> 0
print("Nothing!")

隱式表達式為False的是如下狀況:

– None

– False

– 數值0

– 空的容器或序列(字元串也是一種序列)

– 用戶自定義類中,如果定義了__len__()或者__nonzero__(),並且被調用後返回0或者False

while 循環

while的就是循環和if的綜合體,是一種單純的基於條件的循環,本身沒有遍歷的意思,這是和for_each的本質差別,這種區別比起C/C++中要明確得多,用法如下:

i = 0
while i &< 100: # 笑100遍 print("ha") while True: # 一直笑 print("ha")

5.2.4 函數、生成器和類

還是從幾個例子看起:

def say_hello():
print("Hello!")

def greetings(x="Good morning!"):
print(x)

say_hello() # Hello!
greetings() # Good morning!
greetings("What"s up!") # What"s up!
a = greetings() # 返回值是None

def create_a_list(x, y=2, z=3): # 默認參數項必須放後面
return [x, y, z]

b = create_a_list(1) # [1, 2, 3]
c = create_a_list(3, 3) # [3, 3, 3]
d = create_a_list(6, 7, 8) # [6, 7, 8]

def traverse_args(*args):
for argin args:
print(arg)

traverse_args(1, 2, 3) # 依次列印1, 2, 3
traverse_args("A", "B", "C", "D") # 依次列印A, B, C, D

def traverse_kargs(**kwargs):
for k, v in kwargs.items():
print(k, v)

traverse_kargs(x=3, y=4, z=5) # 依次列印("x", 3), ("y", 4), ("z", 5)
traverse_kargs(fighter1="Fedor", fighter2="Randleman")

def foo(x, y, *args, **kwargs):
print(x, y)
print(args)
print(kwargs)

# 第一個pring輸出(1, 2)
# 第二個print輸出(3, 4, 5)
# 第三個print輸出{"a": 3, "b": "bar"}
foo(1, 2, 3, 4, 5, a=6, b="bar")

其實和很多語言差不多,括弧裡面定義參數,參數可以有默認值,且默認值不能在無默認值參數之前。Python中的返回值用return定義,如果沒有定義返回值,默認返回值是None。參數的定義可以非常靈活,可以有定義好的固定參數,也可以有可變長的參數(args: arguments)和關鍵字參數(kargs: keyword arguments)。如果要把這些參數都混用,則固定參數在最前,關鍵字參數在最後。

Python中萬物皆對象,所以一些情況下函數也可以當成一個變數似的使用。比如前面小節中提到的用字典代替switch-case的用法,有的時候我們要執行的不是通過條件判斷得到對應的變數,而是執行某個動作,比如有個小機器人在坐標(0, 0)處,我們用不同的動作控制小機器人移動:

moves = ["up", "left", "down", "right"]

coord = [0, 0]

for movein moves:
if move == "up": # 向上,縱坐標+1
coord[1] += 1
elif move == "down": # 向下,縱坐標-1
coord[1] -= 1
elif move == "left": # 向左,橫坐標-1
coord[0] -= 1
elif move == "right": # 向右,橫坐標+1
coord[0] += 1
else:
pass
print(coord)

不同條件下對應的是對坐標這個列表中的值的操作,單純的從字典取值就辦不到了,所以就把函數作為字典的值,然後用這個得到的值執行相應動作:

moves = ["up", "left", "down", "right"]

def move_up(x): # 定義向上的操作
x[1] += 1

def move_down(x): # 定義向下的操作
x[1] -= 1

def move_left(x): # 定義向左的操作
x[0] -= 1

def move_right(x): # 定義向右的操作
x[0] += 1

# 動作和執行的函數關聯起來,函數作為鍵對應的值
actions = {
"up": move_up,
"down": move_down,
"left": move_left,
"right": move_right
}

coord = [0, 0]

for movein moves:
actions[move](coord)
print(coord)

把函數作為值取到後,直接加一括弧就能使了,這樣做之後起碼在循環部分看上去很簡潔。有點C裡邊函數指針的意思,只不過更簡單。其實這種用法在之前講排序的時候我們已經見過了,就是operator中的itemgetter。itemgetter(1)得到的是一個可調用對象(callable object),和返回下標為1的元素的函數用起來是一樣的:

def get_val_at_pos_1(x):
return x[1]

heros = [
("Superman", 99),
("Batman", 100),
("Joker", 85)
]

sorted_pairs0 = sorted(heros, key=get_val_at_pos_1)
sorted_pairs1 = sorted(heros, key=lambda x: x[1])

print(sorted_pairs0)
print(sorted_pairs1)

在這個例子中我們用到了一種特殊的函數:lambda表達式。Lambda表達式在Python中是一種匿名函數,lambda關鍵字後面跟輸入參數,然後冒號後面是返回值(的表達式),比如上邊例子中就是一個取下標1元素的函數。當然,還是那句話,萬物皆對象,給lambda表達式取名字也是一點問題沒有的:

some_ops = lambda x, y: x + y + x*y + x**y
some_ops(2, 3) # 2 + 3 + 2*3 + 2^3 = 19

生成器(Generator

生成器是迭代器的一種,形式上看和函數很像,只是把return換成了yield,在每次調用的時候,都會執行到yield並返回值,同時將當前狀態保存,等待下次執行到yield再繼續:

# 從10倒數到0
def countdown(x):
while x &>= 0:
yield x
x -= 1

for i in countdown(10):
print(i)

# 列印小於100的斐波那契數
def fibonacci(n):
a = 0
b = 1
while b &< n: yield b a, b = b, a + b for x in fibonacci(100): print(x)

生成器和所有可迭代結構一樣,可以通過next()函數返回下一個值,如果迭代結束了則拋出StopIteration異常:

a = fibonacci(3)
print(next(a)) # 1
print(next(a)) # 1
print(next(a)) # 2
print(next(a)) # 拋出StopIteration異常

Python3.3以上可以允許yield和return同時使用,return的是異常的說明信息:

# Python3.3以上可以return返回異常的說明
def another_fibonacci(n):
a = 0
b = 1
while b &< n: yield b a, b = b, a + b return "No more ..." a = another_fibonacci(3) print(next(a)) # 1 print(next(a)) # 1 print(next(a)) # 2 print(next(a)) # 拋出StopIteration異常並列印No more消息

類(Class

Python中的類的概念和其他語言相比沒什麼不同,比較特殊的是protected和private在Python中是沒有明確限制的,一個慣例是用單下劃線開頭的表示protected,用雙下劃線開頭的表示private:

class A:
"""Class A"""
def __init__(self, x, y, name):
self.x = x
self.y = y
self._name = name

def introduce(self):
print(self._name)

def greeting(self):
print("What"s up!")

def __l2norm(self):
return self.x**2 + self.y**2

def cal_l2norm(self):
return self.__l2norm()

a = A(11, 11, "Leonardo")
print(A.__doc__) # "Class A"
a.introduce() # "Leonardo"
a.greeting() # "What"s up!"
print(a._name) # 可以正常訪問
print(a.cal_l2norm()) # 輸出11*11+11*11=242
print(a._A__l2norm()) # 仍然可以訪問,只是名字不一樣
print(a.__l2norm()) # 報錯: "A" object has no attribute "__l2norm"

類的初始化使用的是__init__(self,),所有成員變數都是self的,所以以self.開頭。可以看到,單下劃線開頭的變數是可以直接訪問的,而雙下劃線開頭的變數則觸發了Python中一種叫做name mangling的機制,其實就是名字變了下,仍然可以通過前邊加上「_類名」的方式訪問。也就是說Python中變數的訪問許可權都是靠自覺的。類定義中緊跟著類名字下一行的字元串叫做docstring,可以寫一些用於描述類的介紹,如果有定義則通過「類名.__doc__」訪問。這種前後都加雙下劃線訪問的是特殊的變數/方法,除了__doc__和__init__還有很多,這裡就不展開講了。

Python中的繼承也非常簡單,最基本的繼承方式就是定義類的時候把父類往括弧里一放就行了:

class B(A):
"""Class B inheritenced from A"""
def greeting(self):
print("How"s going!")

b = B(12, 12, "Flaubert")
b.introduce() # Flaubert
b.greeting() # How"s going!
print(b._name()) # Flaubert
print(b._A__l2norm()) # 「私有」方法,必須通過_A__l2norm訪問

5.2.5 map, reduce和filter

map可以用於對可遍歷結構的每個元素執行同樣的操作,批量操作:

map(lambda x: x**2, [1, 2, 3, 4]) # [1, 4, 9, 16]

map(lambda x, y: x + y, [1, 2, 3], [5, 6, 7]) # [6, 8, 10]

reduce則是對可遍歷結構的元素按順序進行兩個輸入參數的操作,並且每次的結果保存作為下次操作的第一個輸入參數,還沒有遍歷的元素作為第二個輸入參數。這樣的結果就是把一串可遍歷的值,減少(reduce)成一個對象:

reduce(lambda x, y: x + y, [1, 2, 3, 4]) # ((1+2)+3)+4=10

filter顧名思義,根據條件對可遍歷結構進行篩選:

filter(lambda x: x % 2, [1, 2, 3, 4, 5]) # 篩選奇數,[1, 3, 5]

需要注意的是,對於filter和map,在Python2中返回結果是列表,Python3中是生成器。

5.2.6 列表生成(list comprehension)

列表生成是Python2.0中加入的一種語法,可以非常方便地用來生成列表和迭代器,比如上節中map的兩個例子和filter的一個例子可以用列表生成重寫為:

[x**2 for x in [1, 2, 3, 4]] # [1, 4, 9 16]

[sum(x) for x in zip([1, 2, 3], [5, 6, 7])] # [6, 8, 10]

[x for x in [1, 2, 3, 4, 5] if x % 2] # [1, 3, 5]

zip()函數可以把多個列表關聯起來,這個例子中,通過zip()可以按順序同時輸出兩個列表對應位置的元素對。有一點需要注意的是,zip()不會自動幫助判斷兩個列表是否長度一樣,所以最終的結果會以短的列表為準,想要以長的列表為準的話可以考慮itertools模塊中的izip_longest()。如果要生成迭代器只需要把方括弧換成括弧,生成字典也非常容易:

iter_odd = (x for x in [1, 2, 3, 4, 5] if x % 2)

print(type(iter_odd)) # &

square_dict = {x: x**2 for x in range(5)} # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

至於列表生成和map/filter應該優先用哪種,這個問題很難回答,不過Python創始人Guido似乎不喜歡map/filter/reduce,他曾在表示過一些從函數式編程里拿來的特性是個錯誤。

5.2.7 字元串

Python中字元串相關的處理都非常方便,來看例子:

a = "Life is short, you need Python"
a.lower() # "life is short, you need Python"
a.upper() # "LIFE IS SHORT, YOU NEED PYTHON"
a.count("i") # 2
a.find("e") # 從左向右查找"e",3
a.rfind("need") # 從右向左查找"need",19
a.replace("you", "I") # "Life is short, I need Python"
tokens = a.split() # ["Life", "is", "short,", "you", "need", "Python"]
b = " ".join(tokens) # 用指定分隔符按順序把字元串列表組合成新字元串
c = a + "
" # 加了換行符,注意+用法是字元串作為序列的用法
c.rstrip() # 右側去除換行符
[x for x in a] # 遍歷每個字元並生成由所有字元按順序構成的列表
"Python" in a # True

Python2.6中引入了format進行字元串格式化,相比在字元串中用%的類似C的方式,更加強大方便:

a = "I』m like a {} chasing {}."
# 按順序格式化字元串,"I』m like a dog chasing cars."
a.format("dog", "cars")

# 在大括弧中指定參數所在位置
b = "I prefer {1} {0} to {2} {0}"
b.format("food", "Chinese", "American")

# &>代表右對齊,&>前是要填充的字元,依次輸出:
# 000001
# 000019
# 000256
for i in [1, 19, 256]:
print("The index is {:0&>6d}".format(i))

# &<代表左對齊,依次輸出: # *--------- # ****------ # *******--- for x in ["*", "****", "*******"]: progress_bar = "{:-&<10}".format(x) print(progress_bar) for x in [0.0001, 1e17, 3e-18]: print("{:.6f}".format(x)) # 按照小數點後6位的浮點數格式 print("{:.1e}".format(x)) # 按照小數點後1位的科學記數法格式 print ("{:g}".format(x)) # 系統自動選擇最合適的格式 template = "{name} is {age} years old." c = template.format(name="Tom", age=8)) # Tom is 8 years old. d = template.format(age=7, name="Jerry")# Jerry is 7 years old.

format在生成字元串和文檔的時候非常有用,更多更詳細的用法可以參考Python官網:

7.1. string – Common string operations – Python 2.7.13 documentation

5.2.8 文件操作和pickle

在Python中,推薦用上下文管理器(with-as)來打開文件,IO資源的管理更加安全,而且不用老惦記著給文件執行close()函數。還是舉例子來說明,考慮有個文件name_age.txt,裡面存儲著名字和年齡的關係,格式如下:

Tom,8
Jerry,7
Tyke,3
...

讀取文件內容並全部顯示:

with open("name_age.txt", "r") as f: # 打開文件,讀取模式
lines = f.readlines() # 一次讀取所有行
for linein lines: # 按行格式化並顯示信息
name, age = line.rstrip().split(",")
print("{} is {} years old.".format(name, age))

open()的第一個參數是文件名,第二個參數是模式。文件的模式一般有四種,讀取(r),寫入(w),追加(a)和讀寫(r+)。如果希望按照二進位數據讀取,則將文件模式和b一起使用(wb, r+b…)。

再考慮一個場景,要讀取文件內容,並把年齡和名字的順序交換存成新文件age_name.txt,這時可以同時打開兩個文件:

with open("name_age.txt", "r") as fread, open("age_name.txt", "w") as fwrite:
line = fread.readline()
while line:
name, age = line.rstrip().split(",")
fwrite.write("{},{}
".format(age, name))
line = fread.readline()

有的時候我們進行文件操作是希望把對象進行序列化,那麼可以考慮用pickle模塊:

import pickle

lines = [
"I"m like a dog chasing cars.",
"I wouldn"t know what to do if I caught one...",
"I"d just do things."
]

with open("lines.pkl", "wb") as f: # 序列化並保存成文件
pickle.dump(lines, f)

with open("lines.pkl", "rb") as f: # 從文件讀取並反序列化
lines_back = pickle.load(f)

print(lines_back) # 和lines一樣

注意到,序列化的時候就得使用b模式了。Python2中有個效率更高的pickle叫cPickle,用法和pickle一樣,在Python3中就只有一個pickle。

5.2.9 異常

相比起其他一些語言,在Python中我們可以更大膽地使用異常,因為異常在Python中是非常常見的存在,比如下面這種簡單的遍歷:

a = ["Why", "so", "serious", "?"]

for x in a:
print(x)

當用for進行遍歷時,會對要遍歷的對象調用iter()。這需要給對象創建一個迭代器用來依次返回對象中的內容。為了能成功調用iter(),該對象要麼得支持迭代協議(定義__iter__()),要麼得支持序列協議(定義__getitem__())。當遍歷結束時,__iter__()或者__getitem__()都需要拋出一個異常。__iter__()會拋出StopIteration,而__getitem__()會拋出IndexError,於是遍歷就會停止。

在深度學習中,尤其是數據準備階段,常常遇到IO操作。這時候遇到異常的可能性很高,採用異常處理可以保證數據處理的過程不被中斷,並對有異常的情況進行記錄或其他動作:

for filepathin filelist: # filelist中是文件路徑的列表
try:
with open(filepath, "r") as f:
# 執行數據處理的相關工作
...

print("{} is processed!".format(filepath))
except IOError:
print("{} with IOError!".format(filepath))
# 異常的相應處理
...

5.2.10 多進程(multiprocessing)

深度學習中對數據高效處理常常會需要並行,這時多進程就派上了用場。考慮這樣一個場景,在數據準備階段,有很多文件需要運行一定的預處理,正好有台多核伺服器,我們希望把這些文件分成32份,並行處理:

from multiprocessing import Process#, freeze_support

def process_data(filelist):
for filepathin filelist:
print("Processing {} ...".format(filepath))
# 處理數據
...

if __name__ == "__main__":
# 如果是在Windows下,還需要加上freeze_support()
#freeze_support()

# full_list包含了要處理的全部文件列表
...

n_total = len(full_list) # 一個遠大於32的數
n_processes = 32

# 每段子列表的平均長度
length = float(n_total) / float(n_processes)

# 計算下標,儘可能均勻地劃分輸入文件列表
indices = [int(round(i*length)) for i in range(n_processes+1)]

# 生成每個進程要處理的子文件列表
sublists = [full_list[indices[i]:indices[i+1]] for i in range(n_processes)]

# 生成進程
processes = [Process(target=process_data, args=(x,)) for x in sublists]

# 並行處理
for p in processes:
p.start()

for p in processes:
p.join()

其中 if __name__ == 『__main__』用來標明在import時不包含,但是作為文件執行時運行的語句塊。為什麼不用多線程呢?簡單說就是Python中線程的並發無法有效利用多核,如果有興趣的讀者可以從下面這個鏈接看起:

GlobalInterpreterLock – Python Wiki

5.2.11 os模塊

深度學習中的數據多是文件,所以數據處理階段和文件相關的操作就非常重要。除了文件IO,Python中一些操作系統的相關功能也能夠非常方便地幫助數據處理。想像一下我們有一個文件夾叫做data,下邊有3個子文件夾叫做cat,dog和bat,裡面分別是貓,狗和蝙蝠的照片。為了訓練一個三分類模型,我們先要生成一個文件,裡面每一行是文件的路徑和對應的標籤。定義cat是0,dog是1,bat是2,則可以通過如下腳本:

import os

# 定義文件夾名稱和標籤的對應關係
label_map = {
"cat": 0,
"dog": 1,
"bat": 2
}

with open("data.txt", "w") as f:

# 遍歷所有文件,root為當前文件夾,dirs是所有子文件夾名,files是所有文件名
for root, dirs, filesin os.walk("data"):
for filenamein files:
filepath = os.sep.join([root, filename]) # 獲得文件完整路徑
dirname = root.split(os.sep)[-1] # 獲取當前文件夾名稱
label = label_map[dirname] # 得到標籤
line = "{},{}
".format(filepath, label)
f.write(line)

其中,os.sep是當前操作系統的路徑分隔符,在Unix/Linux中是』/』,Windows中是』\』。有的時候我們已經有了所有的文件在一個文件夾data下,希望獲取所有文件的名稱,則可以用os.listdir():

filenames = os.listdir("data")

os也提供了諸如拷貝,移動和修改文件名等操作。同時因為大部分深度學習框架最常見的都是在Unix/Linux下使用,並且Unix/Linux的shell已經非常強大(比Windows好用太多),所以只需要用字元串格式化等方式生成shell命令的字元串,然後通過os.system()就能方便實現很多功能,有時比os,還有Python中另一個操作系統相關模塊shutil還要方便:

import os, shutil

filepath0 = "data/bat/IMG_000001.jpg"
filepath1 = "data/bat/IMG_000000.jpg"

# 修改文件名
os.system("mv {} {}".format(filepath0, filepath1))
#os.rename(filepath0, filepath1)

# 創建文件夾
dirname = "data_samples"
os.system("mkdir -p {}".format(dirname))
#if not os.path.exists(dirname):
# os.mkdir(dirname)

# 拷貝文件
os.system("cp {} {}".format(filepath1, dirname))
#shutil.copy(filepath1, dirname)


你想更深入了解學習Python知識體系,你可以看一下我們花費了一個多月整理了上百小時的幾百個知識點體系內容:

【超全整理】《Python自動化全能開發從入門到精通》筆記全放送


爬取了豆瓣 Python 標籤下所有書籍,為大家推薦一些Python入門的好書!

title = "推薦Python入門的好書"
version = "2.0"
author = "Zhiliao_01"
update_date = "2017-5-18"
commit = "添加源碼地址,修改錯字及標點"

---------2017-5-18-----------

github源碼地址:Alenwang1/Python_Practice

---------2017-5-12-----------

一、 前言

學習一門編程語言最重要的有兩點:

  1. 一本可以幫助你概覽知識框架的好書;
  2. 持續不斷地實踐和總結。

二、 找到一本適合自己的書

在學習編程的初級階段,一本好的入門書籍往往可以讓你打下堅實的基礎,從而提高學習效率,不用往複。

個人能力、精力畢竟是有限的。所以,爬取了豆瓣 Python 標籤下所有的書籍,我們從那些評論數、星數都較高的書籍開始找起,選擇適合我們的 Python 入門書籍。

我有了一些功夫,從400多本 Python 相關書籍中篩選了一些,並按照內容進行了分類,主要包括:

  • Python基礎
  • Python進階
  • Python高階
  • 演算法與數據結構
  • 網路數據採集|爬蟲
  • Web開發
  • 科學計算機器學習
  • 計算機安全

這些分類下的書籍,都是該分類下書籍中經過時間和群眾檢驗過的。但是,他們適合的讀者人群不太相似。比如:介紹 Python 基礎教程的書籍中就有適合孩子看的、適合非計算機專業人群看的和有一定編程基礎人看的。

所以,大家應該根據自己的情況來選擇書籍。為了方便大家更好的選擇,每個書目都對應了豆瓣的鏈接(由於知乎的BUG,目前取消了超鏈接,大家下載Excel表格進行查看吧!),大家可以通過其他網友的評論來自行選擇。有一些是我看過的書籍,我在書目後打了簡略的標籤

Python_Book_List

01 Python 書籍內容分類

Python基礎

  • Python編程快速上手 推薦使用
  • Think Python 推薦使用
  • Python基礎教程
  • A Byte of Python
  • Python for Informatics
  • Python編程:從入門到實踐 推薦使用
  • Invent Your Own Computer Games with Python 適合孩童
  • 從Python開始學編程 編程思想
  • Python Tutorial 作者:Python之父
  • 與孩子一起學編程老少咸宜的編程書
  • Python核心編程(第二版)

Python進階

  • Effective Python Pythonic
  • Fluent Python
  • Python Cookbook
  • 編寫高質量代碼:改善Python程序的91個建議

Python高階

  • Python源碼剖析

演算法與數據結構

  • Problem Solving with Algorithms and Data Structures Using Python 在線交互閱讀
  • 網路數據採集|爬蟲
  • Python網路數據採集推薦
  • 用Python寫網路爬蟲

Web開發

  • Flask Web開發:基於Python的Web應用開發實戰 Flask教程
  • The Definitive Guide to Django Django教程

科學計算機器學習

  • 利用Python進行數據分析 Numpypandas
  • 機器學習實戰

安全

  • Python灰帽子

另外,我將 Python 標籤下爬取的400多條書目保存在了EXCEL中,並存在了百度雲盤。大家需要可以自取。

Excel 百度雲盤下載鏈接: Python_book_list

三、 實踐項目

選擇一個剛興趣的方向趕快實踐起來才是正道。這方面可以看看另一個問題

Python 的練手項目有哪些值得推薦? 中的回答。

四、助學工具

在學習Python的時候一些可以幫助你學習的工具也是必不可少的。這裡就要推薦一下我們自己的APP—— 知了學習社 ,可能有廣告的嫌疑。不過,我們的APP確實是在移動端唯一可以用來互動式學習Python的工具。

特別是工作和課業比較繁忙的同學,在空閑的時間拿出手機就可以系統的學習Python了!

當然,除了Python之外,還有HTMLCSS、JS、經管以及心理學的基礎課程。這些課程也是免費分享給大家的。

APP目前還在第一版的測試階段,可能還存在著諸多不足,希望大家可以參與進來提出更多的建議。一起維護一個知識分享的社區。

如果,你也想分享你自己的知識和技能,也可以在知了學習社上傳自己的課程。謝謝大家!

APP下載地址: 知了APP下載鏈接


最近在寫一個入門教程,題主可以參考下。

包括博客和視頻

python教程大綱

  1. python 變數視頻地址
  2. python 運算符視頻地址
  3. python 語句視頻地址
  4. python list、tuple、dict、set視頻地址
  5. python 函數初窺視頻地址
  6. python 類視頻地址
  7. python 模塊視頻地址
  8. python 爬蟲
  9. python web


最好方法就是去看python中文官方文檔,給你個鏈接Python 教程,又不是每個人都看過實驗樓,沒什麼靠不靠譜的,要認真學了不靠譜的也靠譜了。


玄魂工作室--Coding - 知乎專欄 正在做關於python的教程,可以關注

最新文章

  • 不後悔一時衝動,因為收穫太多感動這是關於此話題的第二篇,也是最後一篇,說多了就矯情了!昨天,有一點衝動,破天荒的發了一篇抱怨的文章《我免費發布的… 查看全文

    玄魂工作室-玄魂 · 27 分鐘前

    1 贊 · 1 條評論

  • Python黑帽編程2.7 異常處理Python黑帽編程2.7 異常處理異常是個很寬泛的概念,如果程序沒有按預想的執行,都可以說是異常了。遇到一些特殊情況沒處… 查看全文

    玄魂工作室-玄魂 · 12 小時前

    6 贊

  • 我免費發布的東西,你拿去賣錢,我不平衡2016-08-11 玄魂工作室-玄魂 一年多前,錄了一套 Kali Linux web滲透測試--初級教程(23課時)。當時發布在51cto在線教… 查看全文

    玄魂工作室-玄魂 · 1 天前

    191 贊 · 40 條評論

  • 如何學python-第十五課 linux下的python腳本編程今天我們不講具體的python技巧。今天講講在linux下,從腳本創建到執行的過程。如果需要看win下的,可以留言,我會再做一… 查看全文

    李三思 · 1 天前

    15 贊 · 5 條評論

  • 玄魂工作室--咪嚕妹啦啦啦~最近是不是都被這個運動員妹紙的表情包刷屏了呢;這麼歡脫的妹紙在運動界堪稱一股清新的「泥石流」~讓我們為我國… 查看全文

    玄魂工作室-玄魂 · 3 天前

    3 贊 · 8 條評論

  • Python黑帽編程2.6 模塊我們已經學習了如何在你的程序中定義一次函數而重用代碼。如果你想要在其他程序中重用很多函數,那麼你該如何編寫程序呢… 查看全文

    玄魂工作室-玄魂 · 3 天前

    9 贊 · 1 條評論

  • 如何學python-第十四課 lambda及其使用上節課我們介紹了一些列表的高級使用方法。在本節,我們更進一步,討論一下lambda和它的一些使用。(嗯,我不會討論戈登… 查看全文

    李三思 · 3 天前

    19 贊 · 5 條評論

  • 單身狗,你並不孤單今天是七夕,互聯網上一片虐狗的言論。但我是個善良人,我想給單身狗帶來一點精神上的慰藉,即便是孤單,也要優雅,更何… 查看全文

    玄魂工作室-玄魂 · 4 天前

    25 贊 · 15 條評論

  • 每周一書-2016年8月9日很高興今天收到電子工業出版社的美女編輯 安娜 的贈書:(3本),這是幾本今年剛出的新書,我們也會重點宣傳一下,優先對外贈送。這裡先透露一下,下周會贈送Bootstrap這本書,想要的小夥伴… 查看全文

    玄魂工作室-玄魂 · 4 天前

    1 贊 · 2 條評論

  • 如何學python-第十三課 列表進階-切片 列表推導式歡迎回來。在上一節課,我們學習了邏輯運算符和成員運算符。按照慣例,這節課我們講點其他的東西,換換腦筋。本節課我們… 查看全文

    李三思 · 4 天前

    5 贊

  • Python黑帽編程2.5 函數寫了幾節的基礎知識,真心感覺有點力不從心。這塊的內容說實話,看文檔是最好的方式,本人的寫作水平,真的是找不出更好… 查看全文

    玄魂工作室-玄魂 · 4 天前

    24 贊 · 2 條評論

  • 每周一書計劃-2016.8.8每周一書計劃雖然現在互聯網上的知識足夠豐富,雖然搜索引擎足夠強大,雖然我們大部分時間都被碎片化,但是在這個煩亂、… 查看全文

    玄魂工作室-玄魂 · 5 天前

    20 贊 · 9 條評論

  • 如何學python-第十二課 邏輯運算符-成員運算符上一節我們介紹了元組和字典。這節課我們討論點別的換換腦筋,聊聊邏輯運算符和成員運算符(有些人也把這個翻譯成身份運… 查看全文

    李三思 · 5 天前

    10 贊 · 3 條評論

  • Python黑帽編程2.4 流程式控制制本節要介紹的是Python編程中和流程式控制制有關的關鍵字和相關內容。2.4.1 IF …..ELSE 先上一段代碼:#!/usr/bin/python # … 查看全文

    玄魂工作室-玄魂 · 5 天前

    7 贊

  • 如何學python-第十一課 元組與字典歡迎回來。上一期的如何學python里,我們討論了函數。我們今天將要學習的是兩種類似於列表(list)類型的數據類型。我們先… 查看全文

    李三思 · 7 天前

    3 贊 · 2 條評論

  • 如何學python-第十課 函數在上一節課里,我們學習了一些關於錯誤檢測和錯誤處理的知識。這節課我們來學習函數。我們將會介紹什麼是函數,以及如何… 查看全文

    李三思 · 9 天前

    11 贊 · 2 條評論

  • Python黑帽編程2.3 字元串、列表、元組、字典和集合本節要介紹的是Python裡面常用的幾種數據結構。通常情況下,聲明一個變數只保存一個值是遠遠不夠的,我們需要將一組或多… 查看全文

    玄魂工作室-玄魂 · 9 天前

    15 贊 · 5 條評論

  • 如何學python-第九課 tryexcept-錯誤與異常人非聖賢,孰能無過?寫程序的時候難免會遇到一些問題。本篇文章會介紹一些寫程序時常見的錯誤,並解釋一下其中的道理。… 查看全文

    李三思 · 9 天前

    7 贊 · 8 條評論

  • Python黑帽編程2.2 數值類型數值類型,說白了就是處理各種各樣的數字,Python中的數值類型包括整型、長整型、布爾、雙精度浮點、十進位浮點和複數,… 查看全文

    玄魂工作室-玄魂 · 10 天前

    2 贊 · 3 條評論

  • 2016阿里安全峰會重點資料下載風聲與暗算,無中又生有:威脅情報應用的那些事兒內容整理:https://yq.aliyun.com/articles/57700PDF下載:· Webs… 查看全文

    玄魂工作室-玄魂 · 10 天前

    32 贊 · 2 條評論

  • 如何學python-第八課 流程式控制制-For,While,循環語句,初見『函數』循環語句也許你會問,什麼是『循環』?在腳本程序里,循環就是『在一定情況下一次又一次的執行某些代碼』。舉個例子來說… 查看全文

    李三思 · 10 天前

    7 贊 · 4 條評論

  • 如何學python-第七課 列表型變數 列表方法 列表索引在上一篇文章里,我們介紹了if語句、elif語句和else語句以及條件判斷語句。我們今天來說點流程式控制制之外的東西:列表。列… 查看全文

    李三思 · 10 天前

    17 贊 · 5 條評論

  • 2016烏雲白帽資料下載2016烏雲白帽資料下載鏈接: http://pan.baidu.com/s/1mhEENcG 密碼: 7g57· 問題討論請加qq群:Hacking (1群… 查看全文

    玄魂工作室-玄魂 · 11 天前

    69 贊 · 6 條評論

  • Python黑帽編程2.1 Python編程哲學本節的內容有些趣味性,涉及到很多人為什麼會選擇Python,為什麼會喜歡這門語言。我帶大家膜拜下Python作者的Python之禪… 查看全文

    玄魂工作室-玄魂 · 11 天前

    267 贊 · 40 條評論

  • Python黑帽編程 2.0 第二章概述於 20世紀80年代末,Guido van Rossum發明了Python,初衷據說是為了打發聖誕節的無趣,1991年首次發布,是ABC語言的繼承… 查看全文

    玄魂工作室-玄魂 · 15 天前

    13 贊

  • 如何學python-第六課 流程式控制制-IF,ELSE,條件語句在上一篇文章里,我們介紹了流程式控制制的概念,並介紹了布爾類型。今天,我們會把上節課學到的東西與 if、else結合起來使… 查看全文

    李三思 · 15 天前

    8 贊 · 6 條評論

  • Python黑帽編程1.5 使用Wireshark練習網路協議分析1.5.0.1 本系列教程說明本系列教程,採用的大綱母本為《Understanding Network Hacks Attack and Defense with Python… 查看全文

    玄魂工作室-玄魂 · 16 天前

    71 贊 · 17 條評論

  • 如何學python-第五課 流程式控制制初階 布爾類型當我們寫程序的時候,我們首要思考的問題就是,程序接收什麼樣的輸入,產生什麼樣的輸出。控制用戶的輸入,進行一系列處… 查看全文

    李三思 · 16 天前

    10 贊

  • 如何學python-第四課 基本的用戶輸入譯者註:原作者留的練習任務都比較靈活,並不是具體的要求。而根據我自身的經驗,很多同學看到這種需要探索精神的要求,… 查看全文

    李三思 · 17 天前

    8 贊 · 6 條評論

  • 如何學python-第三課 基礎字元串操作在上一篇文章中,我們學習了有關變數和輸出的一些基礎知識。大家應該還記得在上一篇文章中出現的字元串類型(string)吧… 查看全文

    李三思 · 18 天前

    7 贊 · 5 條評論

  • 如何學python-第二課 基礎輸出/變數/變數類型在python和其他主流的腳本語言里,有幾樣東西會在你在漫長的編程生涯里一直伴隨著你——不外乎輸出,變數,以及變數… 查看全文

    李三思 · 18 天前

    10 贊 · 4 條評論

  • 如何學python-第一課 入門簡介最近在論壇上閑逛的時候,我發現了一些相當不錯的python腳本編程的文章。不過,這些文章也有它們的局限性,因為它們更多… 查看全文

    李三思 · 18 天前

    62 贊 · 13 條評論

  • 烏雲掛了,知識庫的文章卻在流傳朋友圈都在轉,我也湊個熱鬧,涉及侵權或者違反法律,請通知我。烏雲知識庫文章:鏈接:http://pan.baidu.com/s/1hsGy5d… 查看全文

    玄魂工作室-玄魂 · 19 天前

    120 贊 · 25 條評論

  • Python黑帽編程1.3 Python運行時與包管理工具0.1 本系列教程說明本系列教程,採用的大綱母本為《Understanding Network Hacks Attack and Defense with Python》一… 查看全文

    玄魂工作室-玄魂 · 19 天前

    26 贊 · 14 條評論

  • 關於《Python黑帽編程1.2》引發的基礎知識與工具的爭議上一篇文章《Python黑帽編程1.2 基於VS Code構建Python開發環境》在知乎發布後,首先引起了大家關於工具的爭議。開發Pyt… 查看全文

    玄魂工作室-玄魂 · 22 天前

    133 贊 · 39 條評論

  • Python黑帽編程1.2 基於VS Code構建Python開發環境Python黑帽編程1.2 基於VS Code構建Python開發環境0.1 本系列教程說明本系列教程,採用的大綱母本為《Understanding N… 查看全文

    玄魂工作室-玄魂 · 23 天前

    120 贊 · 42 條評論

  • Python黑帽編程1.1虛擬機安裝和配置 Kali Linux 2016Python黑帽編程1.1虛擬機安裝和配置 Kali Linux 20160.1 本系列教程說明本系列教程,採用的大綱母本為《Understanding … 查看全文

    玄魂工作室-玄魂 · 24 天前

    93 贊 · 35 條評論

  • 使用you-get下載視頻網站視頻或其他使用you-get下載視頻網站視頻或其他文/玄魂 目錄使用you-get下載視頻網站視頻或其他前言1.1 下載、安裝依賴exe安裝pip安裝Antigen安裝Git 克隆源碼Homebrew 安… 查看全文

    玄魂工作室-玄魂 · 1 個月前

    23 贊 · 9 條評論

  • asp.net core 開發環境準備1.1 安裝sdk和運行時瀏覽器打開網址https://www.microsoft.com/net/download, 到.Net Core下載頁面。根據操作系統,下… 查看全文

    玄魂工作室-玄魂 · 1 個月前

    5 贊 · 1 條評論

  • Python黑客編程基礎3網路數據監聽和過濾Python黑客編程3網路數據監聽和過濾 課程的實驗環境如下:? 操作系統:kali Linux 2.0? 編程工具:Wing ID… 查看全文

    玄魂工作室-玄魂 · 2 個月前

    380 贊 · 14 條評論

  • debian(kali Linux) 安裝net Coredebian(kali Linux) 安裝net Corecurl -sSL https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0-preview1/scripts… 查看全文

    玄魂工作室-玄魂 · 3 個月前

  • 嗅探、中間人sql注入、反編譯--例說桌面軟體安全性問題今天這篇文章不準備講太多理論,講我最近遇到的一個案例。從技術上講,這個例子沒什麼高深的,還有一點狗屎運的成分,但… 查看全文

    玄魂工作室-玄魂 · 3 個月前

    6 贊 · 2 條評論

  • Python黑客編程2 入門demo--zip暴力破解上一篇文章,我們在Kali Linux中搭建了基本的Python開發環境,本篇文章為了拉近Python和大家的距離,我們寫一個暴力破解… 查看全文

    玄魂工作室-玄魂 · 3 個月前

    16 贊 · 3 條評論

  • kali linux Python 黑客編程1 開發環境初始化為什麼要選擇Python?Python作為目前Linux系統下最流行的編程語言之一,對於安全工作者的作用可以和C++相提並論。Python… 查看全文

    玄魂工作室-玄魂 · 3 個月前

    15 贊 · 1 條評論

  • kali 在線教學群 第一次 公開課 小結(1)


最好的入門指南就是Python文檔,可以看官方的英文原版, 也可以看中文版手冊:Python 入門指南

另外建議你多練習,邊學邊練習,事半功倍

動手實踐很重要

動手實踐很重要

動手實踐很重要

另外,和別人交流也很重要,推薦多逛論壇,看看別人遇到哪些問題。

推薦論壇:

Python論壇-國內最好的Python中文社區:Python論壇|Python教程|Django教程|Python框架


1.要做好一個程序員,是不是應該首先學會利用搜索引擎呢?

2.做為一個知乎er,提問前是不是應該先確定所問問題是否有答案呢?

3.鑒於知乎對新手的高門檻,你的問題被回答的幾率這麼低,沒有激起你尋找別的解決問題的途徑的激情嗎?

4.建議Python入門指南和實驗樓靠譜不靠譜分開問,這兩個問題,第一個問題已有答案,第二個問題還沒有。知乎和論壇還是有區別的。

5.附上不假思索隨手搜索的結果截圖:


Python教程 - 廖雪峰的官方網站

專欄:Python爬蟲入門教程


1.你的目的是什麼?

我學習python大概只用了2個月的時間(後面會有詳細介紹),其中還有大半個月因為工作忙,幾乎沒有碰python。這並不是說python有多容易或是我有多聰明,而是想強調一個問題,你學習python的目的是什麼?這是你在學習python之前必須要問自己的問題,也是最總要的問題。我說說我的回答,我學習python是為了進行股票的量化分析,而且是屬於比較簡單的數據分析,因此我的目的非常明確,在學習的過程中有非常明確的目標,能夠產生持續的動力。如果你沒有一個明確的學習目的,相信我,你有很大的可能會中途放棄。與其中途放棄,還不如去干點其他對你更有意義的事情。

我學習了兩個月就能做一些簡單的數據分析,就是因為我有一個明確的目標,有解決各種問題的動力。

下面我的經歷可能只適合那些不準備將編程當成工作,而只是為了解決某項問題的人。

2.我學習python的經歷

背景

說學習過程前,先說說我的知識背景。

我不能算編程零基礎的人,之前斷斷續續學過一些編程語言,包括VB、VBA、甚至是C之類的。不過每次學習最多也就學到數據類型、if while等控制語句、函數就戛然而止,原因就是因為沒有具體的目的,很快就因為其他事情放棄了。之前其實也有學過python,是學習廖雪峰的課程,不過只看到print,可以說幾乎是沒有學。這是第二次重新開始學習python。不過之前看過一些編程語言的好處就是對一些編程的基本概念還是有所了解,不至於是完全的小白。

我的英語不好,大學學的全忘光了,所以不能像知乎上的高手一樣直接看官方文檔。

第一階段

我最初選擇的是python3,廖雪峰的課程,學到《高級特性》那個章節,發現專門python3的學習資料太少了,網上到處都是python2的,因此又重頭看廖雪峰的python2課程(關於python3和python2的選擇後面會講到),這次看到了《函數式編程》章節,也就推進了一個章節,而且還沒看完,到我回答這個問題為止都還沒有繼續往下學。

因為在學習廖雪峰課程的時候在出差,比較閑,只花了兩周左右的時間。我的學習方式主要是一個一個的敲課程上的代碼。不過學了下來感覺好像還是不能用python解決什麼問題,不過好在對python有一個整體的感覺了。

我推薦新手先學習,至少是先看一下廖雪峰的課程,這是因為他的課程比較簡短而全面,可以很快對python有一個大體的感受,這一點非常總要。這讓你在學習其他課程的時候,至少知道在說的是什麼問題。而且如果你學習python有明確的目的,完全可以不用看完整個課程,我沒有學完整個課程,一樣在用python分析股票。

第二階段:

大致學習了一下廖雪峰的課程後,我感覺還是沒法解決什麼問題,而且有些地方也說的不是很清楚。因此我選擇了學《笨辦法學 Python(第四版)》和《簡明Python教程》,這兩本書在網上都能搜索到。

學習方法還是一行一行的敲代碼,花了大概三、四周的時間。一行一行的敲代碼來學習非常重要,絕對不能只看書,否則真正敲代碼的時候會有種不知如何下手的感覺。

簡單說說對這兩本書的感受,《笨辦法學 Python(第四版)》是以問答的形式展開,與傳統的形式不太一樣,但全書的學習進度安排比較合理,從最基礎的內容到稍高級的內容都有涉及,循循漸進,且充滿反覆練習。這本書尤其好的地方是教導你如何閱讀代碼,以及自己鑽研問題和尋求答案的能力。學完之後對如何用python解決實際問題會有一種初步的感受,會覺得自己好像現在能用python解決一些實際問題了。

這本書我只學了前45課,後面因為和我的目標關係不大,就暫時沒有學習。不過直到現在我對於類、實例之類的都還沒有搞的特別明白。

《簡明Python教程》是在《笨辦法學 Python(第四版)》之後開始學的。有點像傳統的教科書風格,不過更注重教導如何解決實際問題。這本書我到現在都還沒有敲完。

另外,還可以把《Python學習手冊(第4版)》作為參考書籍,一些python中不太清楚的細節可以直接查詢這本書。

學習到了這個階段,我對於使用python解決我的實際問題已經有了一些信心,而且也不至於完全不知道如何下手,因此我就直接轉入了處理實際項目的階段。

第三階段:

我學習python的目標是為了做股票分析,因此直接選擇聚寬作為分析平台。我的具體目標是要計算不同指數的等權和加權市盈率。在編寫這個程序的過程中,遇到無數的問題,不過還好我整個邏輯比較清晰,大致設計出了要得到最後的結果我中間需要一些什麼樣的過程。

在經歷這些過程中,我發現對很多東西都沒有概念,這個時候就要反覆的在網上查詢,搜索。我推薦菜鳥教程的python基礎教程,用這個來做很多python的查詢非常方便。完成項目的過程,需要的就是解決項目中 一個又一個細小的問題,當我在項目中解決的問題越多,我發現對python也就越來越熟悉。

在實際解決項目的階段,就不能糾結於看某本書了,需要的是你去查詢資料,去自我解決問題。

3.關於python2和python3的選擇

其實隨便那個版本都影響不大,你可以先去看看菜鳥教程的python基礎教程中對於兩個版本差異的說明,其實大多數情況下,差異很小,了解之後你就不會感到無所適從。

不過我建議用python2,因為網上的學習資料非常豐富,我從python3轉到python2就是因為發現網上很多基礎的學習資料都只有python2的版本。學習了python2之後,適當了解兩者的差別,很快就能適應python3.

4.關於IDE的選擇

這個得看你的項目大小和你準備幹什麼。如果你只是做做小項目,解決一些小問題,那直接用python自帶的IDLE完全沒有問題,我的整個自學過程就是在IDLE上完成的。IDLE比較簡答,沒有複雜的設置,能讓你專註於編程本身。不過需要注意,有時候安裝python後IDLE會出現一些莫名其妙的異常,這個時候只有更換了。

不過如果你喜歡折騰,pycharm也是很好的選擇,用社區版就行了,免費的。pycharm有一些比較方便編程的處理,可以幫助你形成良好的編程習慣。

最近我發現python的個發行版winpython也很不錯,裡面已經內置好了各種庫,還提供spyder,ipython notebook這些。最重要的是winpython一般不會出現安裝問題,這對初學者會非常友好。


前幾天我有個很好的學經濟的兄弟問我如何快速入門Matlab。

我想了想,告訴他的第一件事,就是沒必要看大部頭的編程書。以下大概是我想表達的意思:

我自從大二學完C語言和C++之後,書桌上就從來沒有過一本編程的書籍。

所以我的編程水平很渣,哈哈

但是作為土木直博男,我目前每天都在用Python, Fortran 77, C++,以及Matlab寫代碼,

用valgrind調試,用latex和beamer做文檔。

用Linux系統工作。

這些都不是通過看一本一本的書學來的。

我的方法是,

搜索YouTube入門視頻,

下載Hello World小代碼,進而下載和自己工作內容相近的代碼

或者就是自己實驗室的代碼,

藉助於搜索引擎這個大『辭典』,慢慢把代碼讀懂,並同時改造成自己想要的樣子。

在這個過程中不斷學習,總結,提升。

然後就算基本會用這個編程語言了。

有了這些基礎,可以再看一些系統的介紹文本,進一步提升對整個語言的理解。

我覺得這是比較高效的編程學習方法。


這裡分享幾個python的學習文檔 支持pdf epub mobi電子書下載

入門級的文檔

Python 語言參考手冊

Python 入門指南

《從零開始學 Python》(第二版)

Python 之旅

對python有初步了解之後 可以通過開發項目來進一步提高能力 這裡推薦幾個使用python開發web的文檔

Flask 用戶指南

Django 搭建簡易博客教程

Django 中文文檔 1.8

如果你是想使用python開發爬蟲程序:

Python 爬蟲學習系列教程

Scrapy 中文指南


學習一門變成語言,我覺得先應該考慮一下學習這門語言的目標。像是python這樣,和C、C++有點不同,python主要是用他大量的庫,學習的目標不同,用的庫不同,所要學的東西大相徑庭。所以說,最好先考慮一下目標,然後配合這個目標方向選取一兩個庫開始一起學習,也不會太無聊。

我覺得python做的事情大概可以分為幾大塊,科學計算(包括圖像處理,數據處理,各種機器學習啥的),網路部分(後端,通信,爬蟲),互動GUI(了解不多,有TK,pygame之類)。

因為我學python主要是為了做科學計算,那就以這個方向為例,說明一下我覺得應該怎麼學習。

首先是安裝,由於python有大量的庫,最好要找一個庫管理的工具,我推薦anaconda(鏈接在這裡Download Anaconda Now!),anaconda自身包含了python和一些常用庫,標準的anaconda已經集成了常用的numpy,scipy,pandas等庫,注意:安裝的路徑不能有空格和中文。

裝好了以後打開cmd試一下

這樣就說明裝好了。

平時如果是不需要保存的代碼,可以用ipython(python的互動界面,anaconda包含了),而平時在寫的時候推薦使用Pycharm(edu版免費也沒什麼區別,鏈接在這裡PyCharm :: Download Latest Version of PyCharm),使用pycharm的時候記得要設置編譯器在settings-&>Project-&>Project Interpreter里,不設置應該不能運行。

(以上是安裝部分,也是我在學習python遇到的最大問題之一,像python這樣比較直觀的語言,學會安裝和安裝其他庫,一隻腳就踏進門了)

學習:

python的本身內容學習推薦廖雪峰的教程(鏈接在這裡Python教程),如果沒其他語言基礎的話,我認為教程看到遞歸這裡就差不多了,可以開始考慮做點有意思的東西了。

如果是做科學計算數據分析啥的,肯定需要用其他的庫(例如numpy,scipy),這些庫的學習英語過關的話,盡量看官網的documentation找下裡面的guide,以numpy為例(鏈接Quickstart tutorial),當然英語看著累的話可以去找下中文教程,像是numpy這樣的常用庫會有比較多,看的時候注意下教程用的python版本2和3區別可能比較大。

剩下的學習部分,先挖個坑,想到在寫。

關於庫的擴展,建議使用conda或者pip安裝,anaconda集成了這兩個工具(conda應該就是它自己),這兩個工具都很智能的比如我想安裝openpyxl,就在cmd里輸入conda install openpyxl或者pip install openpyxl就可以了,它會自動搜索合適的whl下載並安裝,偶爾會出現找不到合適的包的情況(例如windows平台的tensorflow),可以用『pip install whl的下載地址』 這樣安裝,一般包的官網會有說明。

下圖是安裝scikit-learn的樣子,已經安裝了,他會自動理解為更新。

常用庫可以參考(鏈接哪些 Python 庫讓你相見恨晚?)

這裡列一個我自己常用的庫(括弧里是說明):

numpy(矩陣運算,和matlab有點像)

scipy(官網說是科學工具,裡面有一些各種各樣的功能,比較零碎,例如載入.mat文件的)

pandas(數據io)

matlibplot(繪統計圖庫,功能強大但是難用)

seaborn(基於matlibplot開發,比matlibplot好用不少)

tensorflow(超強大的機器學習的庫,用來做cnn很不錯。缺點是上手有點難,他過於底層,且編寫的思維應該是gpu的編寫思維,先聲明幹嘛,在做事情;以及很不好安裝(怪我用windows咯))

openpyxl(處理excel,個人認為在處理excel上比pandas好用)

PIL(用於處理圖像,可能還有其他功能,我主要用PIL的image)

plotly(是plotly的python端,畫統計圖用,很好看但是不怎麼好用還要聯網,效果例如下圖:)

暫時寫到這裡,想到再補


有點基礎後推薦兩本不錯的書:python cookbook python 參考手冊,姿勢大漲喲


我該怎麼開始學習編程?

這個鏈接希望對你有所幫助。