有一本學Python的書,也許你還沒有關注到,它在bookauthority的Python類目中排名第三,要勝過太多太多的Python書。那就是《Python編程快速上手 讓繁瑣工作自動化》。
就它本身來說,這本書不會讓你變成一個職業(yè)軟件開發(fā)者,就像幾節(jié)吉他課程不會讓你變成一名搖滾巨星。但如果你是辦公室職員、管理者、學術研究者,或使用計算機來工作或娛樂的任何人,你將學到編程的基本知識,這樣就能將下面這樣一些簡單的任務自動化:
對人來說,這些任務簡單,但很花時間。它們通常很瑣碎、很特殊,沒有現(xiàn)成的軟件可以完成。有一點編程知識,就可以讓計算機為你完成這些任務。
本書沒有設計成參考手冊,它是初學者指南。編碼風格有時候違反最佳實踐(例如,有些程序使用全局變量),但這是一種折中,讓代碼更簡單,以便學習。
下面分享一下第一章節(jié),希望你的Python編程語言可以從這里開始。
Python編程語言有許多語法結(jié)構(gòu)、標準庫函數(shù)和交互式開發(fā)環(huán)境功能。好在,你可以忽略大多數(shù)內(nèi)容。你只需要學習部分內(nèi)容,就能編寫一些方便的小程序。
但在動手之前,你必須學習一些基本編程概念。就像魔法師培訓,你可能認為這些概念既深奧又啰嗦,但有了一些知識和實踐,你就能像魔法師一樣指揮你的計算機,完成難以置信的事情。
本章有幾個例子,我們鼓勵你在交互式環(huán)境中輸入它們。交互式環(huán)境讓你每次執(zhí)行一條Python指令,并立即顯示結(jié)果。使用交互式環(huán)境對于了解基本Python指令的行為是很好的,所以你在閱讀時要試一下。做過的事比僅僅讀過的內(nèi)容,更令人印象深刻。
1.1 在交互式環(huán)境中輸入表達式
啟動IDLE就運行了交互式環(huán)境,這是和Python一起安裝的。在Windows上,打開“開始”菜單,選擇“All ProgramsPython 3.3”,然后選擇“IDLE(Python GUI)”。在OS X上,選擇“ApplicationsMacPython 3.3IDLE”。在Ubuntu上,打開新的終端窗口并輸入idle3。
一個窗口會出現(xiàn),包含>>>提示符,這就是交互式環(huán)境。在提示符后輸入2 + 2,讓Python做一些簡單的算術。
>>> 2 + 2
4
IDLE窗口現(xiàn)在應該顯示下面這樣的文本:
Python 3.3.2 (v3.3.2:d047928ae3f6, May 16 2013, 00:06:53) [MSC v.1600 64 bit
(AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> 2 + 2
4
>>>
在Python中,2 + 2稱為“表達式”,它是語言中最基本的編程結(jié)構(gòu)。表達式包含“值”(例如2)和“操作符”(例如+),并且總是可以求值(也就是歸約)為單個值。這意味著在Python代碼中,所有使用表達式的地方,也可以使用一個值。
在前面的例子中,2 + 2被求值為單個值4。沒有操作符的單個值也被認為是一個表達式,盡管它求值的結(jié)果就是它自己,像下面這樣:
>>> 2
2
錯誤沒關系!
如果程序包含計算機不能理解的代碼,就會崩潰,這將導致Python顯示錯誤信息。錯誤信息并不會破壞你的計算機,所以不要害怕犯錯誤?!氨罎ⅰ敝皇且馕吨绦蛞馔獾赝V箞?zhí)行。
如果你希望對一條錯誤信息了解更多,可以在網(wǎng)上查找這條信息的準確文本,找到關于這個錯誤的更多內(nèi)容。也可以查看http://nostarch.com/automatestuff/,這里有常見的Python錯誤信息和含義的列表。
Python表達式中也可以使用大量其他操作符。例如,表 1-1 列出了Python的所有數(shù)學操作符。
表1-1 數(shù)學操作符
數(shù)學操作符的操作順序(也稱為“優(yōu)先級”)與數(shù)學中類似。**操作符首先求值,接下來是-*、/、//和%操作符,從左到右計算。+和-操作符最后求值,也是從左到右計算。如果需要,可以用括號來改變通常的優(yōu)先級。在交互式環(huán)境中輸入下列表達式:
>>> 2 + 3 * 6
20
>>> (2 + 3) * 6
30
>>> 48565878 * 578453
28093077826734
>>> 2 ** 8
256
>>> 23 / 7
3.2857142857142856
>>> 23 // 7
3
>>> 23 % 7
2
>>> 2 + 2
4
>>> (5 - 1) * ((7 + 1) / (3 - 1))
16.0
在每個例子中,作為程序員,你必須輸入表達式,但Python完成較難的工作,將它求值為單個值。Python將繼續(xù)求值表達式的各個部分,直到它成為單個值,如圖1-1所示。
圖1-1 表達式求值將它歸約為單個值
將操作符和值放在一起構(gòu)成表達式的這些規(guī)則,是 Python 編程語言的基本部分,就像幫助我們溝通的語法規(guī)則一樣。下面是例子:
This is a grammatically correct English sentence.
This grammatically is sentence not English correct a.
第二行很難解釋,因為它不符合英語的規(guī)則。類似地,如果你輸入錯誤的 Python指令,Python也不能理解,就會顯示出錯誤信息,像下面這樣:
>>> 5 +
File "<stdin>", line 1
5 +
^
SyntaxError: invalid syntax
>>> 42 + 5 + * 2
File "<stdin>", line 1
42 + 5 + * 2
^
SyntaxError: invalid syntax
你總是可以在交互式環(huán)境中輸入一條指令,檢查它是否能工作。不要擔心會弄壞計算機:最壞的情況就是Python顯示出錯信息。專業(yè)的軟件開發(fā)者在編寫代碼時,常常會遇到錯誤信息。
1.2 整型、浮點型和字符串數(shù)據(jù)類型
記住,表達式是值和操作符的組合,它們可以通過求值成為單個值?!皵?shù)據(jù)類型”是一類值,每個值都只屬于一種數(shù)據(jù)類型。表1-2列出了Python中最常見的數(shù)據(jù)類型。例如,值-2和30屬于“整型”值。整型(或int)數(shù)據(jù)類型表明值是整數(shù)。帶有小數(shù)點的數(shù),如3.14,稱為“浮點型”(或float)。請注意,盡管42是一個整型,但42.0是一個浮點型。
表1-2 常見數(shù)據(jù)類型
Python程序也可以有文本值,稱為“字符串”,或strs(發(fā)音為“stirs”)。總是用單引號(')包圍住字符串(例如'Hello'或'Goodbye cruel world!'),這樣Python就知道字符串的開始和結(jié)束。甚至可以有沒有字符的字符串,稱為“空字符串”。第4章更詳細地解釋了字符串。
如果你看到錯誤信息SyntaxError: EOL while scanning string literal,可能是忘記了字符串末尾的單引號,如下面的例子所示:
>>> 'Hello world!
SyntaxError: EOL while scanning string literal
1.3 字符串連接和復制
根據(jù)操作符之后的值的數(shù)據(jù)類型,操作符的含義可能會改變。例如,在操作兩個整型或浮點型值時,+是相加操作符。但是,在用于兩個字符串時,它將字符串連接起來,成為“字符串連接”操作符。在交互式環(huán)境中輸入以下內(nèi)容:
>>> 'Alice' + 'Bob'
'AliceBob'
該表達式求值為一個新字符串,包含了兩個字符串的文本。但是,如果你對一個字符串和一個整型值使用加操作符,Python就不知道如何處理,它將顯示一條錯誤信息。
>>> 'Alice' + 42
Traceback (most recent call last):
File "<pyshell#26>", line 1, in <module>
'Alice' + 42
TypeError: Can't convert 'int' object to str implicitly
錯誤信息Can't convert 'int' object to str implicitly表示Python認為,你試圖將一個整數(shù)連接到字符串'Alice'。代碼必須顯式地將整數(shù)轉(zhuǎn)換為字符串,因為Python不能自動完成轉(zhuǎn)換。(1.6節(jié)“程序剖析”在討論函數(shù)時,將解釋數(shù)據(jù)類型轉(zhuǎn)換。)
在用于兩個整型或浮點型值時,-*-操作符表示乘法。但-*-操作符用于一個字符串值和一個整型值時,它變成了“字符串復制”操作符。在交互式環(huán)境中輸入一個字符串乘一個數(shù)字,看看效果。
>>> 'Alice' * 5
'AliceAliceAliceAliceAlice'
該表達式求值為一個字符串,它將原來的字符串重復若干次,次數(shù)就是整型的值。字符串復制是一個有用的技巧,但不像字符串連接那樣常用。
*操作符只能用于兩個數(shù)字(作為乘法),或一個字符串和一個整型(作為字符串復制操作符)。否則,Python將顯示錯誤信息。
>>> 'Alice' * 'Bob'
Traceback (most recent call last):
File "<pyshell#32>", line 1, in <module>
'Alice' * 'Bob'
TypeError: can't multiply sequence by non-int of type 'str'
>>> 'Alice' * 5.0
Traceback (most recent call last):
File "<pyshell#33>", line 1, in <module>
'Alice' * 5.0
TypeError: can't multiply sequence by non-int of type 'float'
Python不理解這些表達式是有道理的:你不能把兩個單詞相乘,也很難將一個任意字符串復制小數(shù)次。
1.4 在變量中保存值
“變量”就像計算機內(nèi)存中的一個盒子,其中可以存放一個值。如果你的程序稍后將用到一個已求值的表達式的結(jié)果,就可以將它保存在一個變量中。
1.4.1 賦值語句
用“賦值語句”將值保存在變量中。賦值語句包含一個變量名、一個等號(稱為賦值操作符),以及要存儲的值。如果輸入賦值語句spam = 42,那么名為spam的變量將保存一個整型值42。
可以將變量看成一個帶標簽的盒子,值放在其中,如圖1-2所示。
圖1-2 spam = 42 就像是告訴程序“變量spam現(xiàn)在有整數(shù)42放在里面”
例如,在交互式環(huán)境中輸入以下內(nèi)容:
? >>> spam = 40
>>> spam
40
>>> eggs = 2
? >>> spam + eggs
42
>>> spam + eggs + spam
82
? >>> spam = spam + 2
>>> spam
42
第一次存入一個值,變量就被“初始化”(或創(chuàng)建)?。此后,可以在表達式中使用它,以及其他變量和值?。如果變量被賦了一個新值,老值就被忘記了?。這就是為什么在例子結(jié)束時,spam求值為42,而不是40。這稱為“覆寫”該變量。在交互式環(huán)境中輸入以下代碼,嘗試覆寫一個字符串:
>>> spam = 'Hello'
>>> spam
'Hello'
>>> spam = 'Goodbye'
>>> spam
'Goodbye'
就像圖1-3中的盒子,這個例子中的spam變量保存了'Hello',直到你用'Goodbye'替代它。
圖1-3 如果一個新值賦給變量,老值就被遺忘了
1.4.2 變量名
表1-3中有一些合法變量名的例子。你可以給變量取任何名字,只要它遵守以下3條規(guī)則:
1.只能是一個詞。
2.只能包含字母、數(shù)字和下劃線。
3.不能以數(shù)字開頭。
表1-3 有效和無效的變量名
變量名是區(qū)分大小寫的。這意味著,spam、 SPAM、Spam和sPaM是4個不同的變量。變量用小寫字母開頭是Python的慣例。
本書的變量名使用了駝峰形式,沒有用下劃線。也就是說,變量名用lookLikeThis,而不是looking_like_this。一些有經(jīng)驗的程序員可能會指出,官方的Python代碼風格PEP 8,即應該使用下劃線。我喜歡駝峰式,這沒有錯,并認為PEP 8本身“愚蠢的一致性是頭腦狹隘人士的心魔”:
“一致地滿足風格指南是重要的。但最重要的是,知道何時要不一致,因為有時候風格指南就是不適用。如果有懷疑,請相信自己的最佳判斷。”
好的變量名描述了它包含的數(shù)據(jù)。設想你搬到一間新屋子,搬家紙箱上標的都是“東西”。你永遠找不到任何東西!本書的例子和許多Python的文檔,使用spam、eggs和bacon等變量名作為一般名稱(受到Monty Python的“Spam”短劇的影響),但在你的程序中,具有描述性的名字有助于提高代碼可讀性。
1.5 第一個程序
雖然交互式環(huán)境對于一次運行一條 Python指令很好,但要編寫完整的Python程序,就需要在文件編輯器中輸入指令?!拔募庉嬈鳌鳖愃朴贜otepad或TextMate這樣的文本編輯器,它有一些針對輸入源代碼的特殊功能。要在IDLE中打開文件編輯器,請選擇FileNew ?File。
出現(xiàn)的窗口中應該包含一個光標,等待你輸入,但它與交互式環(huán)境不同。在交互式環(huán)境中,按下回車,就會執(zhí)行Python指令。文件編輯器允許輸入許多指令,保存為文件,并運行該程序。下面是區(qū)別這兩者的方法:
現(xiàn)在是創(chuàng)建第一個程序的時候了!在文件編輯器窗口打開后,輸入以下內(nèi)容:
? # This program says hello and asks for my name.
? print('Hello world!')
print('What is your name?') # ask for their name
? myName = input()
? print('It is good to meet you, ' + myName)
? print('The length of your name is:')
print(len(myName))
? print('What is your age?') # ask for their age
myAge = input()
print('You will be ' + str(int(myAge) + 1) + ' in a year.')
在輸入完源代碼后保存它,這樣就不必在每次啟動IDLE時重新輸入。從文件編輯器窗口頂部的菜單,選擇File?Save As。在“Save As”窗口中,在輸入框輸入hello.py,然后點擊“Save”。
在輸入程序時,應該過一段時間就保存你的程序。這樣,如果計算機崩潰,或者不小心退出了IDLE,也不會丟失代碼。作為快捷鍵,可以在Windows和Linux上按Ctrl-S,在OS X上按?-S,來保存文件。
在保存文件后,讓我們來運行程序。選擇Run?Run Module,或按下F5鍵。程序?qū)⒃诮换ナ江h(huán)境窗口中運行,該窗口是首次啟動IDLE時出現(xiàn)的。記住,必須在文件編輯器窗口中按F5,而不是在交互式環(huán)境窗口中。在程序要求輸入時,輸入你的名字。在交互式環(huán)境中,程序輸出應該看起來像這樣:
Python 3.3.2 (v3.3.2:d047928ae3f6, May 16 2013, 00:06:53) [MSC v.1600 64 bit
(AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> ================================ RESTART ================================
>>>
Hello world!
What is your name?
Al
It is good to meet you, Al
The length of your name is:
2
What is your age?
4
You will be 5 in a year.
>>>
如果沒有更多代碼行要執(zhí)行,Python程序就會“中止”。也就是說,它停止運行。(也可以說Python程序“退出”了。)
可以通過點擊窗口上部的X,關閉文件編輯器。要重新加載一個保存了的程序,就在菜單中選擇File?Open?,F(xiàn)在請這樣做,在出現(xiàn)的窗口中選擇hello.py,并點擊“Open”按鈕。前面保存的程序hello.py應該在文件編輯器窗口中打開。
1.6 程序剖析
新程序在文件編輯器中打開后,讓我們快速看一看它用到的Python指令,逐一查看每行代碼。
1.6.1 注釋
下面這行稱為“注釋”。
? # This program says hello and asks for my name.
Python會忽略注釋,你可以用它們來寫程序注解,或提醒自己代碼試圖完成的事。這一行中,#標志之后的所有文本都是注釋。
有時候,程序員在測試代碼時,會在一行代碼前面加上#,臨時刪除它。這稱為“注釋掉”代碼。在你想搞清楚為什么程序不工作時,這樣做可能有用。稍后,如果你準備還原這一行代碼,可以去掉#。
Python也會忽略注釋之后的空行。在程序中,想加入空行時就可以加入。這會讓你的代碼更容易閱讀,就像書中的段落一樣。
1.6.2 print()函數(shù)
print()函數(shù)將括號內(nèi)的字符串顯示在屏幕上。
? print('Hello world!')
print('What is your name?') # ask for their name
代碼行print('Hello world!')表示“打印出字符串'Hello world!'的文本”。Python執(zhí)行到這行時,你告訴Python調(diào)用print()函數(shù),并將字符串“傳遞”給函數(shù)。傳遞給函數(shù)的值稱為“參數(shù)”。請注意,引號沒有打印在屏幕上。它們只是表示字符串的起止,不是字符串的一部分。
也可以用這個函數(shù)在屏幕上打印出空行,只要調(diào)用print()就可以了,括號內(nèi)沒有任何東西。
在寫函數(shù)名時,末尾的左右括號表明它是一個函數(shù)的名字。這就是為什么在本書中你會看到print(),而不是print。第2章更詳細地探討了函數(shù)。
1.6.3 input()函數(shù)
函數(shù)等待用戶在鍵盤上輸入一些文本,并按下回車鍵。
? myName = input()
這個函數(shù)求值為一個字符串,即用戶輸入的文本。前面的代碼行將這個字符串賦給變量myName。
你可以認為input()函數(shù)調(diào)用是一個表達式,它求值為用戶輸入的任何字符串。如果用戶輸入'Al',那么該表達式就求值為myName = 'Al'。
1.6.4 打印用戶的名字
接下來的print()調(diào)用,在括號間包含表達式'It is good to meet you, ' + myName。
? print('It is good to meet you, ' + myName)
要記住,表達式總是可以求值為一個值。如果'Al'是上一行代碼保存在myName中的值,那么這個表達式就求值為'It is good to meet you, Al'。這個字符串傳給print(),它將輸出到屏幕上。
1.6.5 len()函數(shù)
你可以向len()函數(shù)傳遞一個字符串(或包含字符串的變量),然后該函數(shù)求值為一個整型值,即字符串中字符的個數(shù)。
? print('The length of your name is:')
print(len(myName))
在交互式環(huán)境中輸入以下內(nèi)容試一試:
>>> len('hello')
5
>>> len('My very energetic monster just scarfed nachos.')
46
>>> len('')
0
就像這些例子,len(myName)求值為一個整數(shù)。然后它被傳遞給print(),在屏幕上顯示。請注意,print()允許傳入一個整型值或字符串。但如果在交互式環(huán)境中輸入以下內(nèi)容,就會報錯:
>>> print('I am ' + 29 + ' years old.')
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
print('I am ' + 29 + ' years old.')
TypeError: Can't convert 'int' object to str implicitly
導致錯誤的原因不是print()函數(shù),而是你試圖傳遞給print()的表達式。如果在交互式環(huán)境中單獨輸入這個表達式,也會得到同樣的錯誤。
>>> 'I am ' + 29 + ' years old.'
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
'I am ' + 29 + ' years old.'
TypeError: Can't convert 'int' object to str implicitly
報錯是因為,只能用+操作符加兩個整數(shù),或連接兩個字符串。不能讓一個整數(shù)和一個字符串相加,因為這不符合Python的語法??梢允褂米址姹镜恼麛?shù),修復這個錯誤。這在下一節(jié)中解釋。
1.6.6 str()、int()和float()函數(shù)
如果想要連接一個整數(shù)(如29)和一個字符串,再傳遞給print(),就需要獲得值'29'。它是29的字符串形式。str()函數(shù)可以傳入一個整型值,并求值為它的字符串形式,像下面這樣:
>>> str(29)
'29'
>>> print('I am ' + str(29) + ' years old.')
I am 29 years old.
因為str(29)求值為’29’,所以表達式'I am ' + str(29) + ' years old.'求值為'I am ' + '29' + ' years old.',它又求值為'I am 29 years old.'。這就是傳遞給print()函數(shù)的值。
str()、int()和float()函數(shù)將分別求值為傳入值的字符串、整數(shù)和浮點數(shù)形式。請嘗試用這些函數(shù)在交互式環(huán)境中轉(zhuǎn)換一些值,看看會發(fā)生什么。
>>> str(0)
'0'
>>> str(-3.14)
'-3.14'
>>> int('42')
42
>>> int('-99')
-99
>>> int(1.25)
1
>>> int(1.99)
1
>>> float('3.14')
3.14
>>> float(10)
10.0
前面的例子調(diào)用了str()、int()和float()函數(shù),向它們傳入其他數(shù)據(jù)類型的值,得到了字符串、整型或浮點型的值。
如果想要將一個整數(shù)或浮點數(shù)與一個字符串連接,str()函數(shù)就很方便。如果你有一些字符串值,希望將它們用于數(shù)學運算,int()函數(shù)也很有用。例如,input()函數(shù)總是返回一個字符串,即便用戶輸入的是一個數(shù)字。在交互式環(huán)境中輸入spam = input(),在它等待文本時輸入101。
>>> spam = input()
101
>>> spam
'101'
保存在spam中的值不是整數(shù)101,而是字符串'101'。如果想要用spam中的值進行數(shù)學運算,那就用int()函數(shù)取得spam的整數(shù)形式,然后將這個新值存在spam中。
>>> spam = int(spam)
>>> spam
101
現(xiàn)在你應該能將spam變量作為整數(shù),而不是字符串使用。
>>> spam * 10 / 5
202.0
請注意,如果你將一個不能求值為整數(shù)的值傳遞給int(),Python將顯示出錯信息。
>>> int('99.99')
Traceback (most recent call last):
File "<pyshell#18>", line 1, in <module>
int('99.99')
ValueError: invalid literal for int() with base 10: '99.99'
>>> int('twelve')
Traceback (most recent call last):
File "<pyshell#19>", line 1, in <module>
int('twelve')
ValueError: invalid literal for int() with base 10: 'twelve'
如果需要對浮點數(shù)進行取整運算,也可以用int()函數(shù)。
>>> int(7.7)
7
>>> int(7.7) + 1
8
在你的程序中,最后3行使用了函數(shù)int()和str(),取得適當數(shù)據(jù)類型的值。
? print('What is your age?') # ask for their age
myAge = input()
print('You will be ' + str(int(myAge) + 1) + ' in a year.')
myAge變量包含了input()函數(shù)返回的值。因為input()函數(shù)總是返回一個字符串(即使用戶輸入的是數(shù)字),所以你可以使用int(myAge)返回字符串的整型值。這個整型值隨后在表達式int(myAge) + 1中與1相加。
相加的結(jié)果傳遞給str()函數(shù):str(int(myAge) + 1)。然后,返回的字符串與字符串'You will be '和' in a year.'連接,求值為一個更長的字符串。這個更長的字符串最終傳遞給print(),在屏幕上顯示。
假定用戶輸入字符串'4',保存在myAge中。字符串'4'被轉(zhuǎn)換為一個整型,所以你可以對它加1。結(jié)果是5。str()函數(shù)將這個結(jié)果轉(zhuǎn)化為字符串,這樣你就可以將它與第二個字符串'in a year.'連接,創(chuàng)建最終的消息。這些求值步驟如圖1-4所示。
文本和數(shù)字相等判斷
雖然數(shù)字的字符串值被認為與整型值和浮點型值完全不同,但整型值可以與浮點值相等。
>>> 42 == '42'
False
>>> 42 == 42.0
True
>>> 42.0 == 0042.000
True
Python進行這種區(qū)分,因為字符串是文本,而整型值和浮點型都是數(shù)字。
圖1-4 如果4保存在myAge中,求值的步驟
1.7 小結(jié)
你可以用一個計算器來計算表達式,或在文本處理器中輸入字符串連接。甚至可以通過復制粘貼文本,很容易地實現(xiàn)字符串復制。但是表達式以及組成它們的值(操作符、變量和函數(shù)調(diào)用),才是構(gòu)成程序的基本構(gòu)建塊。一旦你知道如何處理這些元素,就能夠用Python操作大量的數(shù)據(jù)。
最好是記住本章中介紹的不同類型的操作符(+、-、-*-、/、//、%和-**-是數(shù)學操作符,+和-*-是字符串操作符),以及3種數(shù)據(jù)類型(整型、浮點型和字符串)。
我們還介紹了幾個不同的函數(shù)。print()和input()函數(shù)處理簡單的文本輸出(到屏幕)和輸入(通過鍵盤)。len()函數(shù)接受一個字符串,并求值為該字符串中字符的數(shù)目。
在下一章中,你將學習如何告訴Python根據(jù)它擁有的值,明智地決定什么代碼要運行,什么代碼要跳過,什么代碼要重復。這稱為“控制流”,它讓你編寫程序來做出明智的決定。