原文 http://www.hetland.org/python/instant-hacking.php
Instant Hacking[譯文]
譯者: 肯定來過
這是一篇簡短的關於python程式設計語言的入門教程,原文在這裡,翻著詞典翻譯了來!
這是一份對編程藝術的簡短介紹,其中的例子是用python寫成的。(如果你已經知道了該如何編程,但是想簡單瞭解一下python,你可以查閱我的另一篇文章Instant Python。)這篇文章已經被翻譯為意大利、波蘭、日本、塞爾維亞以及巴西葡萄亞語等許多種語言,而且正在被翻譯為韓語。(譯者:當然,現在已經包括了中文版本,只是作者並不知道。)
這篇文章和如何闖入別人的電腦系統之類的東西無關。我不關注那類事情,所以請不要email問我那些東西。
注意:要使此文中的例子正確運行,你應該把它們寫在一個文字檔中,然後用解譯器運行;不要試圖直接在互動方式下運行它們--不是所有的都可以這樣運行。(不要問我和此有關的具體細節。最好查閱python文檔或者email給help@python.org)。
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來說,這非常簡單:
print "Hello, world!"
它從根本上說很象上面的菜譜(儘管要短得多!)。它告訴電腦做什麼:列印“Hello, world!”。如果讓它列印更多的廢話該怎麼做呢?很簡單:
print "Hello, world!"
print "Goodbye, world!"
不比上一個難,是不是?但是不怎麼有趣……我們希望它可以處理更多的元素,就象沙拉菜譜那樣。那麼,我們都有哪些元素呢?首先,有字串,象“Hello, world!”,除此之外還有數字。假設我們打算讓電腦為我們計算矩形的面積。我們可以給它如下的菜譜:
# The Area of a Rectangle
# Ingredients:
width = 20
height = 30
# Instructions:
area = width * height
print area
你大概可以看出它同火腿沙拉菜譜的相似性(儘管有些細微的差別)。但它是如何工作的呢?首先,以#開始的行叫做注釋事實上會被電腦忽略。然而插入象這樣小段的注釋對於增強你程式的可讀性來說是很重要的。
接下來,看起來象 foo = bar 這樣的行叫做賦值。對於 width = 20 這樣的情況來說就是告訴電腦從這裡開始width就代表20了。它還意味著一個名字為“width”的變數從此被建立了(如果它先前已經存在,那麼會被重新覆蓋)。所以,我們以後使用這個變數的時候,電腦就知道了它的值。因此,
width * height
本質上同
20 * 30
一樣會計算出600這個結果,然後賦給名稱為“area”的變數。程式的最後一句在螢幕上列印出變數“area”的值,所以你看到這個程式啟動並執行最終結果僅僅是
600
注意:在某些程式設計語言中,你必須在程式開始的時候告訴電腦你將會用到哪些變數(就象沙拉中的元素)--而python足夠聰明,所以你可以根據需要隨時建立。
4. 反饋
現在,你可以執行一些簡單,或者再複雜一點的計算了。比方說,你或許打算寫一段程式來計算圓形的面積而不是矩形的:
radius = 30
print radius * radius * 3.14
然而,這事實上並不比計算矩形面積的那個程式更有意思。至少在我看來是這樣。它有些僵硬。如果我們看到半徑為31的圓該怎麼辦?怎樣讓電腦知道?這有點象沙拉菜譜中的:“燒3到4分鐘直到火腿熟了為止。”要知道何時燒熟,我們必須檢查。我們需要反饋,或者提示。電腦如何知道我們圓形的半徑?同樣需要輸入資料……我們可以做的是告訴電腦半徑是多少:
radius = input("What is the radius?")
print radius * radius * 3.14
現在程式變得漂亮一些了……input是個被稱為函數的東西。(很快你將學習建立你自己的函數。而input是python內建的函數。)僅僅寫下
input
什麼也不會做……你必須在它的後面放上一對括弧。所以input()可以工作--它會簡單的要求使用者輸入半徑的長度。而上面的那個版本對使用者來說也許更友好一些,因為它首先列印出了一個問題。當我們將諸如提問字串“What is the radius?”之類的東西放在函數調用的括弧中時,這個過程被稱為函數的參數傳遞。括弧中的內容被稱為參數。在上個例子中我們傳遞了一個提問作為參數以便input知道在獲得答案前應該先列印什麼。
但是獲得的答案如何到達radius變數呢?函數input,調用時,會返回一個值(象許多其它函數一樣)。你不一定非要使用這個值,但象我們這種情況,我們要使用它。這樣,下面這兩個運算式有著很大的差別:
foo = input
bar = input()
foo現在包含input函數本身(所以它事實上可以象foo("What is your age?")這樣使用;這被稱為動態函數調用)而bar包含使用者鍵入的值。
5. 流程
現在我們可以編寫程式執行簡單的任務(運算和列印)並且可以獲得使用者輸入了。這很有用,但仍然局限在按順序執行命令,也就是說--它們必須按照事先安排好的順序執行。大多數火腿沙拉菜譜是象這樣順序或者線性敘述的。但是如果我們打算讓電腦檢查沙拉是否燒好該怎樣告訴它呢?如果燒好了,那麼應該從烘箱裡把它取出來--否則的話,應該接著讓它燒更長一段時間什麼的。我們如何表達這個?
我們想做的,其實是控製程序的流程。它可以從兩個方向執行--要麼拿開火腿,要不繼續讓它留在烘箱裡。我們可以選擇,條件是它是否燒好。這被稱為條件執行。我們可以這樣寫:
temperature = input("What is the temperature of the spam?")
if temperature >; 50:
print "The salad is properly cooked."
else:
print "Cook the salad some more."
意思很明顯:如果溫度超過50(攝氏度),那麼列印出資訊告訴使用者燒好了,否則,告訴使用者再燒制一段時間。
注意:縮排在python中很重要。條件執行(還有迴圈執行以及函數定義--見後面)中的語句塊必須被縮排(而且要縮排同等數量的空格;一個鍵相當於8個空格)以便解譯器可以知道它們從哪裡開始到哪裡結束。這同時也使程式變得更加可讀。
讓我們回到先前的面積計算問題。能看出來這段程式做什麼嗎?
# Area calculation program
print "Welcome to the Area calculation program"
print "---------------------------------------"
print
# Print out the menu:
print "Please select a shape:"
print "1 Rectangle"
print "2 Circle"
#Get the user's choice:
shape = input(">; ")
#Calculate the area:
if shape == 1:
height = input("Please enter the height: ")
width = input("Please enter the width: ")
area = height *width
print "The area is ", area
else:
radius = input("Please enter the radius: ")
area = 3.14 * (radius**2)
print "The area is ", area
這個例子中的新東西:
1. 只使用print本身將列印出一個空行
2. ==檢查兩個值是否相等,與=不同,後者把運算式右側的值賦給左側的變數。這是一個非常重要的差別!
3. **是python的冪運算子--因此半徑的平方被寫成radius**2
4. print能夠列印出不止一個東西。只要用逗號把它們分開就可以了。(它們在輸出時會用單個空格分開。)
這個程式很簡單:它要一個數字,告訴它使用者打算讓它計算矩形或是圓形的面積。然後,使用一個if語句(條件執行)來決定應當執行哪個語句塊計算面積。這兩個語句塊同先前面積計算例子中使用的語句塊本質上是一樣的。留意注釋是如何使代碼變得更加可讀的。編程的第一條戒律就是:“你應當注釋!”無論如何--它都是一個應該養成的好習慣。
練習1:
擴充上面的程式使它包括正方形面積的計算,使用者只要輸入它一條邊的長度就可以了。做這個練習之前你需要瞭解一件事:如果你有兩個以上的選擇,你可以象這樣寫:
if foo == 1:
# Do something...
elif foo == 2:
# Do something else...
elif foo == 3:
# If all else fails...
這裡的elif是意思為“else if”的神秘代碼:)。所以,如foo等於1,做某件事;否則,如果foo等於2,那麼做另外的一些事,等等。你也可以在程式中加入其它的選項--象三角形以及手繪多邊形。隨你的便。
6. 迴圈
順序執行和條件執行僅僅是程式設計三個基本語句塊架構方式中的兩個。第三個則是迴圈執行。在上個段落中我假設了一種情況,檢查火腿是否燒好,但很明顯它並不適用。如果下次檢查時火腿仍然沒燒好該怎麼辦?我們怎麼知道需要檢查多少次?事實上,我們不知道。而且我們也沒必要知道。我們可以要求電腦持續檢查直到燒好了為止。怎麼表達這個?你猜到了--我們使用迴圈,或者說是重複執行。
python有兩種迴圈類型:while迴圈和for迴圈。for迴圈大概是最簡單的。舉個例子:
for food in "spam", "eggs", "tomatoes":
print "I love", food
它的意思是:對於列表"spam", "eggs", "tomatoes"中的每個元素,都列印出你喜歡它。迴圈中的語句塊為每個元素執行一次,而且每次執行,當前的元素都被賦給變數food(在這個例子中)。另外一個例子:
for number in range(1, 100):
print "Hello, world!"
print "Just", 100 - number, "more to go..."
print "Hello, world"
print "That was the last one... Phew!"
函數range返回給定範圍的數字列表(包括第一個數字,不包括最後一個……這個例子中是[1……99])。所以,這樣解釋它:
迴圈體為1(包括)到100(不包括)之間的數字每個執行一次。(哪個是迴圈體以及隨後的運算式事實上做什麼留下來做為練習。)
但這對我們的燒菜問題並沒有實質的協助。如果我們打算檢查火腿一百次,那麼這是個很好的解決方案;但是我們不知道這是否夠--或者太多了。我們只是希望它在溫度達不到(或者,直到它足夠熱--大致某個狀態)的時候持續檢查。所以,我們使用while:
# Spam-cooking program
# Fetch the function sleep
from time import sleep
print "Please start cooking the spam. (I'll be back in 3 minutes.)"
# Wait for 3 minutes (that is, 3*60 seconds)...
sleep(180)
print "I'm baaack :)"
# How hot is hot enough?
hot_enough = 50
temperature = input("How hot is the spam?")
while temperature < hot_enouth:
print "Not hot enough... Cook it a bit more..."
sleep(30)
temperature = input("OK, How hot is it now?")
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開始試每一個可能的數:
number = input("What is the number?")
floor = 0
while floor <= number:
floor = floor + 1
floor = floor - 1
print "The floor of ", number, "is ", floor
注意當floor不再小於(或者等於)給定數時迴圈結束了;我們加了太多1給它。因此我們必須為它減去1。如果我們希望把它應用於完整的數學運算該怎麼辦呢?我們不得不為求每個數的基數("floor"-ing)而寫一次完整的迴圈。這很不舒服……你可能猜到了我們代之以什麼:把它放在我們自己的函數中,命名為“floor”:
def floor(number):
result = 0
while result <= number:
result = result + 1
result = result - 1
return result
這個例子中的新東西……
1. 函數用關鍵字def定義,函數名緊隨其後並且要用括弧把需要的參數括起來。
2. 如果要求函數返回一個值,要使用關鍵字return來處理(它同時也自動結束函數定義)。
定義了函數之後,我們可以象這樣使用它:
x = 2.7
y = floor(2.7)
執行後,y的值應該是2。定義擁有多個參數的函數也是可以的:
def sum(x, y):
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中它們都被稱為函數(因為它們或多或少以同樣的方式定義和使用)。
函數和過程(在其它語言中)的區別在哪裡呢?嗯--就像你在前面的段落裡看到的那樣,函數可以返回一個值。區別就是過程並不返回這樣的值。許多時候,用這種方法把函數劃分為兩種類型--傳回值的和不傳回值的--是很有用的。
不傳回值的函數(過程)可以用作子程式或例行程式。我們調用這些函數,它們製造某些原料,就象泡沫鮮奶之類的。我們可以在很多地方使用這個函數而不需要重寫它的代碼(這被稱為代碼再利用--以後你還會知道,它意義不僅僅在這裡)。
這樣的函數(或過程)的另一個有用性體現在--它改變了環境(例如,把糖和奶油混在一起攪拌,它們的整個外部狀態就變化了)讓我們看個例子:
def hello(who):
print "Hello, ", who
hello("world")
# Prints out "Hello, world"
列印出內容是它一方面的作用,因為這是這個函數唯一需要做的事,它其實是一個典型的所謂過程。但是……它事實上沒有改變它的運行環境,是不是?它怎樣才能改變呢?讓我們試一下:
# The *wrong* way of doing it
age = 0
def setAge(a):
age = a
setAge(100)
print age
# Prints "0"
錯在哪兒?錯在函數setAge建立了它自己的也被命名為age的局部變數,它只在setAge函數內部可用。那如何才可以避免出現這個問題呢?我們可以使用全域變數。
注意:全域變數在python中不常用。它們容易引起不好的程式碼群組織結構,被稱為意大利麵代碼。我這裡使用它們是為了引出更複雜一點的技術問題--如果你可以請盡量避免使用它們。
[color=#FF0000]未譯完。。。[/color]
rockety 回複於:2005-06-06 09:27:59
[color=red]譯完了的,只是不小心,沒在我的blog上貼全,而且也沒有給出縮排。:oops: 今天一併更正了。感謝wolfg轉貼,並給出了正確的縮排。以下是其餘部分:[/color]
通過告訴解譯器一個變數是全域的(用象global age這樣的運算式做),我們事實上
告訴了它在函數之外使用這個變數,而不是重新建立一個新的局部變數。(所以,和局部
相反它是全域的。)因此上面的程式可以象這樣重寫:
# The correct, but not-so-good way of doing it
age=0
def setAge(a):
global age
setAge(100)
print age
# Prints "100"
瞭解對象(隨後談到)後,你會發現更好的解決這個問題的辦法是使用一個有age屬
性和setAge方法的對象。在資料結構那段,你也將會發現一些函數改變它的環境的更好的
例子。
好了--那麼真正的函數是什麼樣?什麼是函數呢,事實上?數學函數象一種“機
器”,獲得輸入然後計算結果。它會每次返回同樣的結果,如果每次提供它同樣的輸入。
例如:
def square(x):
return x*x
這和數學上的函數f(x)=x*x 一樣。它的行為象一個精確的函數,僅僅依賴於它的輸
入,在任何情況下都不改變它的環境。
所以--我這裡描繪了兩種建構函式的方法:一種類型更象是過程,不返回任何結
果;另一種更象是數學上的函數,(幾乎)什麼也不做就是為了返回一個結果。當然,在
這兩種極端事物之間做某些事情是可能的,儘管當函數改變事物的時候,它應該清楚它改
變了。你可以通過標記它們的名字區分它們,例如為“純粹”的函數使用象square這樣的
名詞而對類似過程那樣的函數使用象setAge這樣命令式的名字。
9. 更多類型-資料結構
現在--你已經知道了不少:怎樣輸入輸出,怎樣設計複雜的運演算法則(程式)來執
行數學運算,但是好戲還在後頭呢。
截止目前我們都在程式中使用了哪些成份呢?數字和字串,對不對?沒意思的種
類……現在讓我們引入兩三個其它的成份來讓事情變得更有意思些。
資料結構是種組織資料的成份。(驚奇,吃驚……)單個的資料沒有什麼真正的資料
結構,是不是?但是假設我們需要很多數放在一起做為一個成份--那就需要某種結構。
例如,我們可能想要一個資料列表。那很容易:
[3, 6, 78, 93]
在迴圈那段我提到了列表,但沒真正描述它。好--這裡說的就是你如何建立它。只
需要列出元素,用逗號分開,再加上方括弧就行了。
來看一個計算素數(只能被1和它本身整除的數)的例子:
# Calculate all the primes below 1000
# (Not the best way to do it, but...)
result = [1]
candidates = range(3, 1000)
base = 2
product = base
while candidates:
while product < 1000:
if product in candidates:
candidates.remove(product)
product = product+base
result.append(base)
base = candidates[0]
product = base
del candidates[0]
result.append(base)
print result
這個例子中的新東西……
內建函數range事實上返回一個列表,可以象所有其它列表那樣使用。(它包括第
一個數,但是不包括最後一個數。)
列表可以當作邏輯變數使用。如果它非空,則為true,否則為false。因此,while
candidates意思是“while名稱為candidates的列表非空時”或者簡單的說“while存
在candidates時”。
你可以用if someElement in somelist來檢查一個元素是否在列表中。
你可以用someList.remove(someElement)來刪除someList中的someElement。
你可以用someList.append(something)為一個列表添加元素。事實上,你也可以使
用“+”(象someList = someList+[something])。但是效率不是太高。
你可以通過在列表名之後加上用括弧括起來的表示某元素位置的數字(很奇怪,列
表的第1個元素,位置是0)來獲得列表的某個元素。因此someList[3]是someList
列表的第四個元素(依次類推)。
你可以使用關鍵字del刪除變數。它也可以用來刪除列表中的元素(就象這裡)。
因此del someList[0]刪除someList 列表中的第一個元素。如果刪除前列表是[1, 2,
3],刪除後就變成了[2, 3]。
在繼續敘述索引列表中的元素之前,我簡單解釋一下上面的例子。
這是古老算術的一個版本,稱為“The Sieve of Erastothenes”(類似這樣)。它考量一
系列給定數字(在本例中是一個列表),然後有組織的刪除已知不是素數的數字。如何知
道?只要看看它們是不是可以被分解為其它兩個數就可以了。
我們從一個包含數字[2...999]的候選列表開始--我們知道1是素數(事實上,它可能
是也可能不是,看你問誰了),我們想得到小於1000的所有素數。(事實上,我們的候
選列表是[3...999],但是2也是候選數字,因為它是我們的第一個base)。我們還有個叫result的列表,它任何時間都包含著最新的結果。最初的時候,它只包含1。我們還有個叫base的變數。每次迴圈,我們刪除是它的倍數的數字(它總是候選列表中最小的數)。每次迴圈之後,我們知道剩下的最小的數是素數(因為所有可以分解的數我們都刪除了)。
因此,我們把它加入result,並把它設為新的base,然後從列表裡移除它(這樣就不會對
它重複計算了)。當候選列表為空白時,result列表將包含所有的素數。精巧吧,哈!
思考一下:第一次迴圈有什麼特別嗎?那時base 是2,但它一樣經過了篩選。為什
嗎?為什麼這不發生在其它的base值身上?我們打算移除product時能否確定它在候選列
表中呢?為什嗎?
接下來是什麼呢?哦,是的……索引。還有切片。它們是從python列表中獲得單個
元素的方法。你已經見到了普通的索引行為。它相當簡單。事實上,我已經告訴了你所有
你需要知道的關於它的東西,除了一件事:負數索引從列表的末尾向前計算。所以,
someList[-1]是someList的最後一個元素,someList[-2]是它之前的一個元素,依次類
推。
切片,仍然,對你來說是陌生的。它和索引相似,除了切片可以獲得列表中的所有的
元素,而不僅僅是單個的元素。這如何做呢?象這樣:
food = [“spam”, “spam”, “eggs”, “sausages”, “spam”]
print food[2:4]
# Prints “['eggs', 'sausages']”
10. 繼續抽象-對象和物件導向編程
現在有個比較熱門的詞叫做“物件導向編程”。
就象本段標題暗示的那樣,物件導向編程僅僅是另外一種抽象細節的方式。程式通過
命名將簡單的描述抽象為複雜的操作。在物件導向編程時,我們不僅可以這樣對待程式,
還可以把它們做為對象。(現在,這肯定會讓你吃驚,哈!)例如,如果編寫燒火腿程
序,我們不用編寫很多過程來處理溫度、時間、成份等等,我們可以把它們結合為一個火
腿對象。或者,也許我們可以再有爐子物件和時鐘對象……那麼,象溫度這類事物就變成
了火腿對象的一個屬性,而時間可以從時鐘對象讀取。要使用我們的程式做某些事,我們
可以教給我們的對象某些方法;比如,爐子應當知道如何烹制火腿等。
那麼--在python中我們如何做呢?我們不能直接製造一個對象。不能直接製造一個
爐子,而是做一個菜譜來描述爐子應該是什麼樣。這份菜譜因此就描述了一個被我們稱為
爐子的一類對象。一個非常簡單的爐子類可能是這樣:
class Oven:
def insertSpam(self, spam):
self.spam = spam
def getSpam(self):
return self.spam
這看起來很難理解,還是怎樣呢?
這個例子中的新東西……
對象的類用關鍵字class定義。
類的名稱通常以大寫字母開始,而函數和變數(還有屬性和方法)的名稱以小寫字
母開始。
方法(也就是讓對象知道如何去做的函數和操作)的定義沒有特別,但是要在類的
定義裡面。
所有對象的方法應當有的第一個參數叫做self(或者類似的……)原因很快就清楚
了。
對象的屬性和方法可以這樣來訪問:mySpam.temperature = 2 或者dilbert.be_nice
()。
我能猜到上面例子中的某些東西你仍然不清楚。例如,什麼是self?還有,現在我們
有了對象菜譜(也就是類),我們怎樣事實上構造一個對象呢?
我們先顛倒一下順序。對象通過象引用函數那樣引用類名來建立:
myOven = Oven()
myOven包含了一個Oven對象,通常叫做Oven類的一個執行個體。假設我們也構造好了
一個Spam類,那麼我們可象這樣做:
mySpam = Spam()
myOven.insertSpam(mySpam)
myOven.spam現在將包含mySpam。怎麼回事?因為,我們調用一個對象的某個方法
時,第一個參數,通常稱為self,總是包含對象本身。(巧妙,哈!)這樣,self.spam =spam這一行設定當前Oven對象的spam屬性的值為參數spam。注意它們是兩個不同的事物,儘管在這個例子中它們都被稱為spam。
11. 練習3答案
這是這個運演算法則的一個非常簡潔的版本:
def euclid(a, b):
while b:
a, b = b, a%b
return a
12. 參考
[1]假日火腿沙拉菜譜摘自獺ormel Foods壞繾影娌似住?
Copyright ?nbsp;Magnus Lie Hetland 肯定來過[譯]