1. 程式人生 > >【轉】python入門教程

【轉】python入門教程

這是一篇簡短的關於python程式設計語言的入門教程,原文在這裡,翻著詞典翻譯了來!


這是一份對程式設計藝術的簡短介紹,其中的例子是用python寫成的。(如果你已經知道了該如何程式設計,但是想簡單瞭解一下python,你可以查閱我的另一篇文章Instant Python。)這篇文章已經被翻譯為義大利、波蘭、日本、塞爾維亞以及巴西葡萄亞語等許多種語言,而且正在被翻譯為韓語。(譯者:當然,現在已經包括了中文版本,只是作者並不知道。)

這篇文章和如何闖入別人的計算機系統之類的東西無關。我不關注那類事情,所以請不要email問我那些東西。

注意:要使此文中的例子正確執行,你應該把它們寫在一個文字檔案中,然後用直譯器執行;不要試圖直接在互動方式下執行它們--不是所有的都可以這樣執行。(不要問我和此有關的具體細節。最好查閱python文件或者email給
[email protected]
)。


1. 執行環境

要用python寫程式,你必須先安裝一個python的直譯器。它可以存在於大多數平臺(包括Macintosh、Unix和Windows)。更多與此有關的資訊可以在python的網站上找到。你還應該有一個文字編輯器(象emacs、notepad或者類似的東西)。

2. 程式設計是什麼?


為計算機寫程式其實就是給它一系列的指令告訴它去做什麼。計算機程式在某些方面就象是菜譜,指導我們如何做菜的那種。例如[1]:

假日火腿沙拉

原料:

醃泡汁:
1/4杯酸橙汁
1/4杯低鈉大豆醬油
1/4杯水
1大湯匙植物油
3/4茶匙小茴香
1/2茶匙牛至
1/4茶匙熱胡椒粉
2片丁香、大蒜,搗碎


沙拉:
1份(12盎司)罐裝少鈉午餐肉火腿切成條狀
1個洋蔥,切片
胡椒粉,切好的生菜
12個櫻桃西紅柿,切半

方法:

把醃泡汁裝在有合適蓋子的廣口瓶裡搖勻。用塑料袋裝上火腿,潑上醃泡汁,封住袋口。在電冰箱裡醃製30分鐘。從塑料袋裡取出火腿;準備2大湯匙醃泡汁,在煮鍋裡煮一下。加上火腿、洋蔥、綠色的胡椒。燒3到4分鐘直到火腿熟了為止……

當然,沒有一臺計算機會懂這個……而且即便是懂,大多數計算機也不可能燒製出一份沙拉。那麼,我們該如何讓這些變得對計算機來說更為友好一些呢?從根本上說依賴於兩點:首先,我們必須以計算機可以理解的方式與之交流;其次還要和它談論它能夠做到的事情。

第一點意味著我們必須使用一種語言--一種已經為之準備好了直譯器的程式設計語言,第二點意味著我們不能期望計算機為我們做一份沙拉--但是我們可以讓它做數字累加或者在螢幕上列印東西之類的事情。


3. Hello……

程式設計教程有一個傳統,通常以在螢幕上列印“Hello, world!”這樣的程式做為開始。對python來說,這非常簡單:

  1. print "Hello, world!"
複製程式碼

它從根本上說很象上面的菜譜(儘管要短得多!)。它告訴計算機做什麼:列印“Hello, world!”。如果讓它列印更多的廢話該怎麼做呢?很簡單:

  1. print "Hello, world!"
  2. print "Goodbye, world!"
複製程式碼

不比上一個難,是不是?但是不怎麼有趣……我們希望它可以處理更多的元素,就象沙拉菜譜那樣。那麼,我們都有哪些元素呢?首先,有字串,象“Hello, world!”,除此之外還有數字。假設我們打算讓計算機為我們計算矩形的面積。我們可以給它如下的菜譜:

  1. # The Area of a Rectangle
  2. # Ingredients:
  3. width = 20
  4. height = 30
  5. # Instructions:
  6. area = width * height
  7. print area
複製程式碼

你大概可以看出它同火腿沙拉菜譜的相似性(儘管有些細微的差別)。但它是如何工作的呢?首先,以#開始的行叫做註釋事實上會被計算機忽略。然而插入象這樣小段的註釋對於增強你程式的可讀性來說是很重要的。

接下來,看起來象 foo = bar 這樣的行叫做賦值。對於 width = 20 這樣的情況來說就是告訴計算機從這裡開始width就代表20了。它還意味著一個名字為“width”的變數從此被建立了(如果它先前已經存在,那麼會被重新覆蓋)。所以,我們以後使用這個變數的時候,計算機就知道了它的值。因此,

width * height

本質上同

20 * 30

一樣會計算出600這個結果,然後賦給名稱為“area”的變數。程式的最後一句在螢幕上打印出變數“area”的值,所以你看到這個程式執行的最終結果僅僅是

600

注意:在某些程式設計語言中,你必須在程式開始的時候告訴計算機你將會用到哪些變數(就象沙拉中的元素)--而python足夠聰明,所以你可以根據需要隨時建立。

4. 反饋

現在,你可以執行一些簡單,或者再複雜一點的計算了。比方說,你或許打算寫一段程式來計算圓形的面積而不是矩形的:

  1. radius = 30
  2. print radius * radius * 3.14
複製程式碼

然而,這事實上並不比計算矩形面積的那個程式更有意思。至少在我看來是這樣。它有些僵硬。如果我們看到半徑為31的圓該怎麼辦?怎樣讓計算機知道?這有點象沙拉菜譜中的:“燒3到4分鐘直到火腿熟了為止。”要知道何時燒熟,我們必須檢查。我們需要反饋,或者提示。計算機如何知道我們圓形的半徑?同樣需要輸入資料……我們可以做的是告訴計算機半徑是多少:

  1. radius = input("What is the radius?")
  2. print radius * radius * 3.14
複製程式碼

現在程式變得漂亮一些了……input是個被稱為函式的東西。(很快你將學習建立你自己的函式。而input是python內建的函式。)僅僅寫下

input

什麼也不會做……你必須在它的後面放上一對括號。所以input()可以工作--它會簡單的要求使用者輸入半徑的長度。而上面的那個版本對使用者來說也許更友好一些,因為它首先打印出了一個問題。當我們將諸如提問字串“What is the radius?”之類的東西放在函式呼叫的括號中時,這個過程被稱為函式的引數傳遞。括號中的內容被稱為引數。在上個例子中我們傳遞了一個提問作為引數以便input知道在獲得答案前應該先列印什麼。

但是獲得的答案如何到達radius變數呢?函式input,呼叫時,會返回一個值(象許多其它函式一樣)。你不一定非要使用這個值,但象我們這種情況,我們要使用它。這樣,下面這兩個表示式有著很大的差別:

  1. foo = input
  2. bar = input()
複製程式碼
foo現在包含input函式本身(所以它事實上可以象foo("What is your age?"這樣使用;這被稱為動態函式呼叫)而bar包含使用者鍵入的值。


5. 流程

現在我們可以編寫程式執行簡單的任務(運算和列印)並且可以獲得使用者輸入了。這很有用,但仍然侷限在按順序執行命令,也就是說--它們必須按照事先安排好的順序執行。大多數火腿沙拉菜譜是象這樣順序或者線性敘述的。但是如果我們打算讓計算機檢查沙拉是否燒好該怎樣告訴它呢?如果燒好了,那麼應該從烘箱裡把它取出來--否則的話,應該接著讓它燒更長一段時間什麼的。我們如何表達這個?

我們想做的,其實是控制程式的流程。它可以從兩個方向執行--要麼拿開火腿,要不繼續讓它留在烘箱裡。我們可以選擇,條件是它是否燒好。這被稱為條件執行。我們可以這樣寫:

  1. temperature = input("What is the temperature of the spam?")
  2. if temperature >; 50:
  3.       print "The salad is properly cooked."
  4. else:
  5.       print "Cook the salad some more."
複製程式碼

意思很明顯:如果溫度超過50(攝氏度),那麼打印出資訊告訴使用者燒好了,否則,告訴使用者再燒製一段時間。

注意:縮排在python中很重要。條件執行(還有迴圈執行以及函式定義--見後面)中的語句塊必須被縮排(而且要縮排同等數量的空格;一個鍵相當於8個空格)以便直譯器可以知道它們從哪裡開始到哪裡結束。這同時也使程式變得更加可讀。

讓我們回到先前的面積計算問題。能看出來這段程式做什麼嗎?

  1. # Area calculation program
  2. print "Welcome to the Area calculation program"
  3. print "---------------------------------------"
  4. print
  5. # Print out the menu:
  6. print "Please select a shape:"
  7. print "1 Rectangle"
  8. print "2 Circle"
  9. #Get the user's choice:
  10. shape = input(">; ")
  11. #Calculate the area:
  12. if shape == 1:
  13.       height = input("Please enter the height: ")
  14.       width = input("Please enter the width: ")
  15.       area = height *width
  16.       print "The area is ", area
  17. else:
  18.       radius = input("Please enter the radius: ")
  19.       area = 3.14 * (radius**2)
  20.       print "The area is ", area
複製程式碼

這個例子中的新東西:
1. 只使用print本身將打印出一個空行
2. ==檢查兩個值是否相等,與=不同,後者把表示式右側的值賦給左側的變數。這是一個非常重要的差別!
3. **是python的冪運算子--因此半徑的平方被寫成radius**2
4. print能夠打印出不止一個東西。只要用逗號把它們分開就可以了。(它們在輸出時會用單個空格分開。)

這個程式很簡單:它要一個數字,告訴它使用者打算讓它計算矩形或是圓形的面積。然後,使用一個if語句(條件執行)來決定應當執行哪個語句塊計算面積。這兩個語句塊同先前面積計算例子中使用的語句塊本質上是一樣的。留意註釋是如何使程式碼變得更加可讀的。程式設計的第一條戒律就是:“你應當註釋!”無論如何--它都是一個應該養成的好習慣。

練習1:


擴充套件上面的程式使它包括正方形面積的計算,使用者只要輸入它一條邊的長度就可以了。做這個練習之前你需要了解一件事:如果你有兩個以上的選擇,你可以象這樣寫:

  1. if foo == 1:
  2.       # Do something...
  3. elif foo == 2:
  4.       # Do something else...
  5. elif foo == 3:
  6.       # If all else fails...
複製程式碼

這裡的elif是意思為“else if”的神祕程式碼。所以,如foo等於1,做某件事;否則,如果foo等於2,那麼做另外的一些事,等等。你也可以在程式中加入其它的選項--象三角形以及任意多邊形。隨你的便。

6. 迴圈

順序執行和條件執行僅僅是程式設計三個基本語句塊架構方式中的兩個。第三個則是迴圈執行。在上個段落中我假設了一種情況,檢查火腿是否燒好,但很明顯它並不適用。如果下次檢查時火腿仍然沒燒好該怎麼辦?我們怎麼知道需要檢查多少次?事實上,我們不知道。而且我們也沒必要知道。我們可以要求計算機持續檢查直到燒好了為止。怎麼表達這個?你猜到了--我們使用迴圈,或者說是重複執行。

python有兩種迴圈型別:while迴圈和for迴圈。for迴圈大概是最簡單的。舉個例子:

  1. for food in "spam", "eggs", "tomatoes":
  2.       print "I love", food
複製程式碼

它的意思是:對於列表"spam", "eggs", "tomatoes"中的每個元素,都打印出你喜歡它。迴圈中的語句塊為每個元素執行一次,而且每次執行,當前的元素都被賦給變數food(在這個例子中)。另外一個例子:

  1. for number in range(1, 100):
  2.       print "Hello, world!"
  3.       print "Just", 100 - number, "more to go..."
  4. print "Hello, world"
  5. print "That was the last one... Phew!"
複製程式碼

函式range返回給定範圍的數字列表(包括第一個數字,不包括最後一個……這個例子中是[1……99])。所以,這樣解釋它:

迴圈體為1(包括)到100(不包括)之間的數字每個執行一次。(哪個是迴圈體以及隨後的表示式事實上做什麼留下來做為練習。)

但這對我們的燒菜問題並沒有實質的幫助。如果我們打算檢查火腿一百次,那麼這是個很好的解決方案;但是我們不知道這是否夠--或者太多了。我們只是希望它在溫度達不到(或者,直到它足夠熱--大致某個狀態)的時候持續檢查。所以,我們使用while:

  1. # Spam-cooking program
  2. # Fetch the function sleep
  3. from time import sleep
  4. print "Please start cooking the spam. (I'll be back in 3 minutes.)"
  5. # Wait for 3 minutes (that is, 3*60 seconds)...
  6. sleep(180)
  7. print "I'm baaack :)"
  8. # How hot is hot enough?
  9. hot_enough = 50
  10. temperature = input("How hot is the spam?")
  11. while temperature < hot_enouth:
  12.       print "Not hot enough... Cook it a bit more..."
  13.       sleep(30)
  14.       temperature = input("OK, How hot is it now?")
  15. print "It's hot enough - You're done!"
複製程式碼
這個例子中的新東西……

1. 有些有用的函式被儲存在模組中而且可以被匯入。此例中我們從python自帶的time模組中匯入了函式sleep(它休止給定的多少秒的時間)。(做你自己的模組當然也是可能的……)

練習2:

寫一個程式,持續從使用者獲得資料然後相加,直到它們的和為100。再寫一個程式,從使用者那裡獲得100個數據,打印出它們的和。

Bigger Programs - Abstraction

如果想知道一本書的大致內容,你不會翻遍所有的頁--你只是看看目錄,是不是?它會列出書的主要內容。現在--想像寫一本菜譜。許多菜譜,像“奶油火腿通心麵”和“瑞士火腿餡餅”很可能包含相同的東西,比如火腿,在這種情況下--你肯定不會打算在每個菜譜裡都重複敘述如何製作火腿。(好了……你事實上可能不做火腿……但是為了做例子,請忍受一下)。你會把製作火腿的菜譜單獨放在一個章節,而僅僅在其它章節裡引用它。這樣--代替在每個菜譜裡都完整的描述,你只要引用章節的名稱就可以了。在計算機程式設計中這被稱為抽象化。

我們是不是已經象這樣運行了某些東西?是的。我們沒有詳細的告訴計算機如何從使用者那裡獲得一個答案(好了--我們沒有真的這樣做……同樣地……我們也沒有真正的在做火腿)而是簡單的使用了input--一個函式來代替。我們事實上可以構造我們自己的函式,來應用於這種型別的抽象化中。

假設我們希望找到小於給定正數的最大整數。例如,給定2.7,這個數應當是2。這往往被稱為給定數的“底線(floor)”。(這事實上可以用python的內建函式int來處理,但是,請再次忍受我拿它作例子……)我們該怎樣做?一個簡單的解決辦法是從0開始試每一個可能的數:

  1. number = input("What is the number?")
  2. floor = 0
  3. while floor <= number:
  4.       floor = floor + 1
  5. floor = floor - 1
  6. print "The floor of ", number, "is ", floor
複製程式碼

注意當floor不再小於(或者等於)給定數時迴圈結束了;我們加了太多1給它。因此我們必須為它減去1。如果我們希望把它應用於完整的數學運算該怎麼辦呢?我們不得不為求每個數的基數("floor"-ing)而寫一次完整的迴圈。這很不舒服……你可能猜到了我們代之以什麼:把它放在我們自己的函式中,命名為“floor”:

  1. def floor(number):
  2.       result = 0
  3.       while result <= number:
  4.             result = result + 1
  5.       result = result - 1
  6.       return result
複製程式碼

這個例子中的新東西……

1. 函式用關鍵字def定義,函式名緊隨其後並且要用括號把需要的引數括起來。
2. 如果要求函式返回一個值,要使用關鍵字return來處理(它同時也自動結束函式定義)。

定義了函式之後,我們可以象這樣使用它:

  1. x = 2.7
  2. y = floor(2.7)
複製程式碼

執行後,y的值應該是2。定義擁有多個引數的函式也是可以的:

  1. def sum(x, y):
  2.      return x + y
複製程式碼

練習3

寫一個函式,用歐幾里德方法尋找兩個數的一個共同因數。工作過程是這樣的:

1. 假設兩個數,a和b,a大於b
2. 重複以下步驟直到b變成0:
1. a變為b的值
2. b變成沒有改變值之前的a除以沒有改變值之前的b的餘數
3. 返回a的最後一個值

提示:

* 使用a和b作為函式的引數
* 簡單的設定a大於b
* x除以z的餘數用表示式 x % z 來計算
* 兩個變數可以象這樣一起賦值:x, y = y, y+1。這裡x被賦以值y(這意味著,y的值此前已經指定)而且y被遞增了1。

7. 深入函式

上面的練習怎麼做?難嗎?還不太清楚函式?別擔心--我還沒完成我的話題呢。

我們構建函式時使用的萃取方法稱為過程抽象,許多程式語言把關鍵字過程同函式一樣使用。事實上,這兩個概念是不一樣的,但是在python中它們都被稱為函式(因為它們或多或少以同樣的方式定義和使用)。

函式和過程(在其它語言中)的區別在哪裡呢?嗯--就像你在前面的段落裡看到的那樣,函式可以返回一個值。區別就是過程並不返回這樣的值。許多時候,用這種方法把函式劃分為兩種型別--返回值的和不返回值的--是很有用的。

不返回值的函式(過程)可以用作子程式或例行程式。我們呼叫這些函式,它們製造某些原料,就象泡沫鮮奶之類的。我們可以在很多地方使用這個函式而不需要重寫它的程式碼(這被稱為程式碼再利用--以後你還會知道,它意義不僅僅在這裡)。

這樣的函式(或過程)的另一個有用性體現在--它改變了環境(例如,把糖和奶油混在一起攪拌,它們的整個外部狀態就變化了)讓我們看個例子:
  1. def hello(who):
  2.       print "Hello, ", who
  3. hello("world")
  4. # Prints out "Hello, world"
複製程式碼

打印出內容是它一方面的作用,因為這是這個函式唯一需要做的事,它其實是一個典型的所謂過程。但是……它事實上沒有改變它的執行環境,是不是?它怎樣才能改變呢?讓我們試一下:
  1. # The *wrong* way of doing it
  2. age = 0
  3. def setAge(a):
  4.       age = a
  5. setAge(100)
  6. print age
  7. # Prints "0"
複製程式碼

錯在哪兒?錯在函式setAge建立了它自己的也被命名為age的區域性變數,它只在setAge函式內部可用。那如何才可以避免出現這個問題呢?我們可以使用全域性變數。

注意:全域性變數在python中不常用。它們容易引起不好的程式碼組織結構,被稱為義大利麵程式碼。我這裡使用它們是為了引出更復雜一點的技術問題--如果你可以請儘量避免使用它們。