一篇不錯(cuò)的Python入門教程
更新時(shí)間:2007年02月08日 00:00:00 作者:
原文 http://www.hetland.org/python/instant-hacking.php
Instant Hacking[譯文]
譯者: 肯定來過
這是一篇簡(jiǎn)短的關(guān)于python程序設(shè)計(jì)語言的入門教程,原文在這里,翻著詞典翻譯了來!
這是一份對(duì)編程藝術(shù)的簡(jiǎn)短介紹,其中的例子是用python寫成的。(如果你已經(jīng)知道了該如何編程,但是想簡(jiǎn)單了解一下python,你可以查閱我的另一篇文章Instant Python。)這篇文章已經(jīng)被翻譯為意大利、波蘭、日本、塞爾維亞以及巴西葡萄亞語等許多種語言,而且正在被翻譯為韓語。(譯者:當(dāng)然,現(xiàn)在已經(jīng)包括了中文版本,只是作者并不知道。)
這篇文章和如何闖入別人的計(jì)算機(jī)系統(tǒng)之類的東西無關(guān)。我不關(guān)注那類事情,所以請(qǐng)不要email問我那些東西。
注意:要使此文中的例子正確運(yùn)行,你應(yīng)該把它們寫在一個(gè)文本文件中,然后用解釋器運(yùn)行;不要試圖直接在交互方式下運(yùn)行它們--不是所有的都可以這樣運(yùn)行。(不要問我和此有關(guān)的具體細(xì)節(jié)。最好查閱python文檔或者email給help@python.org)。
1. 運(yùn)行環(huán)境
要用python寫程序,你必須先安裝一個(gè)python的解釋器。它可以存在于大多數(shù)平臺(tái)(包括Macintosh、Unix和Windows)。更多與此有關(guān)的信息可以在python的網(wǎng)站上找到。你還應(yīng)該有一個(gè)文本編輯器(象emacs、notepad或者類似的東西)。
2. 編程是什么?
為計(jì)算機(jī)寫程序其實(shí)就是給它一系列的指令告訴它去做什么。計(jì)算機(jī)程序在某些方面就象是菜譜,指導(dǎo)我們?nèi)绾巫霾说哪欠N。例如[1]:
假日火腿沙拉
原料:
腌泡汁:
1/4杯酸橙汁
1/4杯低鈉大豆醬油
1/4杯水
1大湯匙植物油
3/4茶匙小茴香
1/2茶匙牛至
1/4茶匙熱胡椒粉
2片丁香、大蒜,搗碎
沙拉:
1份(12盎司)罐裝少鈉午餐肉火腿切成條狀
1個(gè)洋蔥,切片
胡椒粉,切好的生菜
12個(gè)櫻桃西紅柿,切半
方法:
把腌泡汁裝在有合適蓋子的廣口瓶里搖勻。用塑料袋裝上火腿,潑上腌泡汁,封住袋口。在電冰箱里腌制30分鐘。從塑料袋里取出火腿;準(zhǔn)備2大湯匙腌泡汁,在煮鍋里煮一下。加上火腿、洋蔥、綠色的胡椒。燒3到4分鐘直到火腿熟了為止……
當(dāng)然,沒有一臺(tái)計(jì)算機(jī)會(huì)懂這個(gè)……而且即便是懂,大多數(shù)計(jì)算機(jī)也不可能燒制出一份沙拉。那么,我們?cè)撊绾巫屵@些變得對(duì)計(jì)算機(jī)來說更為友好一些呢?從根本上說依賴于兩點(diǎn):首先,我們必須以計(jì)算機(jī)可以理解的方式與之交流;其次還要和它談?wù)撍軌蜃龅降氖虑椤?
第一點(diǎn)意味著我們必須使用一種語言--一種已經(jīng)為之準(zhǔn)備好了解釋器的程序設(shè)計(jì)語言,第二點(diǎn)意味著我們不能期望計(jì)算機(jī)為我們做一份沙拉--但是我們可以讓它做數(shù)字累加或者在屏幕上打印東西之類的事情。
3. Hello……
程序設(shè)計(jì)教程有一個(gè)傳統(tǒng),通常以在屏幕上打印“Hello, world!”這樣的程序做為開始。對(duì)python來說,這非常簡(jiǎn)單:
它從根本上說很象上面的菜譜(盡管要短得多?。?。它告訴計(jì)算機(jī)做什么:打印“Hello, world!”。如果讓它打印更多的廢話該怎么做呢?很簡(jiǎn)單:
不比上一個(gè)難,是不是?但是不怎么有趣……我們希望它可以處理更多的元素,就象沙拉菜譜那樣。那么,我們都有哪些元素呢?首先,有字符串,象“Hello, world!”,除此之外還有數(shù)字。假設(shè)我們打算讓計(jì)算機(jī)為我們計(jì)算矩形的面積。我們可以給它如下的菜譜:
你大概可以看出它同火腿沙拉菜譜的相似性(盡管有些細(xì)微的差別)。但它是如何工作的呢?首先,以#開始的行叫做注釋事實(shí)上會(huì)被計(jì)算機(jī)忽略。然而插入象這樣小段的注釋對(duì)于增強(qiáng)你程序的可讀性來說是很重要的。
接下來,看起來象 foo = bar 這樣的行叫做賦值。對(duì)于 width = 20 這樣的情況來說就是告訴計(jì)算機(jī)從這里開始width就代表20了。它還意味著一個(gè)名字為“width”的變量從此被創(chuàng)建了(如果它先前已經(jīng)存在,那么會(huì)被重新覆蓋)。所以,我們以后使用這個(gè)變量的時(shí)候,計(jì)算機(jī)就知道了它的值。因此,
width * height
本質(zhì)上同
20 * 30
一樣會(huì)計(jì)算出600這個(gè)結(jié)果,然后賦給名稱為“area”的變量。程序的最后一句在屏幕上打印出變量“area”的值,所以你看到這個(gè)程序運(yùn)行的最終結(jié)果僅僅是
600
注意:在某些程序設(shè)計(jì)語言中,你必須在程序開始的時(shí)候告訴計(jì)算機(jī)你將會(huì)用到哪些變量(就象沙拉中的元素)--而python足夠聰明,所以你可以根據(jù)需要隨時(shí)創(chuàng)建。
4. 反饋
現(xiàn)在,你可以執(zhí)行一些簡(jiǎn)單,或者再?gòu)?fù)雜一點(diǎn)的計(jì)算了。比方說,你或許打算寫一段程序來計(jì)算圓形的面積而不是矩形的:
然而,這事實(shí)上并不比計(jì)算矩形面積的那個(gè)程序更有意思。至少在我看來是這樣。它有些僵硬。如果我們看到半徑為31的圓該怎么辦?怎樣讓計(jì)算機(jī)知道?這有點(diǎn)象沙拉菜譜中的:“燒3到4分鐘直到火腿熟了為止。”要知道何時(shí)燒熟,我們必須檢查。我們需要反饋,或者提示。計(jì)算機(jī)如何知道我們圓形的半徑?同樣需要輸入資料……我們可以做的是告訴計(jì)算機(jī)半徑是多少:
現(xiàn)在程序變得漂亮一些了……input是個(gè)被稱為函數(shù)的東西。(很快你將學(xué)習(xí)創(chuàng)建你自己的函數(shù)。而input是python內(nèi)建的函數(shù)。)僅僅寫下
input
什么也不會(huì)做……你必須在它的后面放上一對(duì)括號(hào)。所以input()可以工作--它會(huì)簡(jiǎn)單的要求用戶輸入半徑的長(zhǎng)度。而上面的那個(gè)版本對(duì)用戶來說也許更友好一些,因?yàn)樗紫却蛴〕隽艘粋€(gè)問題。當(dāng)我們將諸如提問字符串“What is the radius?”之類的東西放在函數(shù)調(diào)用的括號(hào)中時(shí),這個(gè)過程被稱為函數(shù)的參數(shù)傳遞。括號(hào)中的內(nèi)容被稱為參數(shù)。在上個(gè)例子中我們傳遞了一個(gè)提問作為參數(shù)以便input知道在獲得答案前應(yīng)該先打印什么。
但是獲得的答案如何到達(dá)radius變量呢?函數(shù)input,調(diào)用時(shí),會(huì)返回一個(gè)值(象許多其它函數(shù)一樣)。你不一定非要使用這個(gè)值,但象我們這種情況,我們要使用它。這樣,下面這兩個(gè)表達(dá)式有著很大的差別:
foo現(xiàn)在包含input函數(shù)本身(所以它事實(shí)上可以象foo("What is your age?")這樣使用;這被稱為動(dòng)態(tài)函數(shù)調(diào)用)而bar包含用戶鍵入的值。
5. 流程
現(xiàn)在我們可以編寫程序執(zhí)行簡(jiǎn)單的任務(wù)(運(yùn)算和打?。┎⑶铱梢垣@得用戶輸入了。這很有用,但仍然局限在按順序執(zhí)行命令,也就是說--它們必須按照事先安排好的順序執(zhí)行。大多數(shù)火腿沙拉菜譜是象這樣順序或者線性敘述的。但是如果我們打算讓計(jì)算機(jī)檢查沙拉是否燒好該怎樣告訴它呢?如果燒好了,那么應(yīng)該從烘箱里把它取出來--否則的話,應(yīng)該接著讓它燒更長(zhǎng)一段時(shí)間什么的。我們?nèi)绾伪磉_(dá)這個(gè)?
我們想做的,其實(shí)是控制程序的流程。它可以從兩個(gè)方向執(zhí)行--要么拿開火腿,要不繼續(xù)讓它留在烘箱里。我們可以選擇,條件是它是否燒好。這被稱為條件執(zhí)行。我們可以這樣寫:
意思很明顯:如果溫度超過50(攝氏度),那么打印出信息告訴用戶燒好了,否則,告訴用戶再燒制一段時(shí)間。
注意:縮進(jìn)在python中很重要。條件執(zhí)行(還有循環(huán)執(zhí)行以及函數(shù)定義--見后面)中的語句塊必須被縮進(jìn)(而且要縮進(jìn)同等數(shù)量的空格;一個(gè)鍵相當(dāng)于8個(gè)空格)以便解釋器可以知道它們從哪里開始到哪里結(jié)束。這同時(shí)也使程序變得更加可讀。
讓我們回到先前的面積計(jì)算問題。能看出來這段程序做什么嗎?
這個(gè)例子中的新東西:
1. 只使用print本身將打印出一個(gè)空行
2. ==檢查兩個(gè)值是否相等,與=不同,后者把表達(dá)式右側(cè)的值賦給左側(cè)的變量。這是一個(gè)非常重要的差別!
3. **是python的冪運(yùn)算符--因此半徑的平方被寫成radius**2
4. print能夠打印出不止一個(gè)東西。只要用逗號(hào)把它們分開就可以了。(它們?cè)谳敵鰰r(shí)會(huì)用單個(gè)空格分開。)
這個(gè)程序很簡(jiǎn)單:它要一個(gè)數(shù)字,告訴它用戶打算讓它計(jì)算矩形或是圓形的面積。然后,使用一個(gè)if語句(條件執(zhí)行)來決定應(yīng)當(dāng)執(zhí)行哪個(gè)語句塊計(jì)算面積。這兩個(gè)語句塊同先前面積計(jì)算例子中使用的語句塊本質(zhì)上是一樣的。留意注釋是如何使代碼變得更加可讀的。編程的第一條戒律就是:“你應(yīng)當(dāng)注釋!”無論如何--它都是一個(gè)應(yīng)該養(yǎng)成的好習(xí)慣。
練習(xí)1:
擴(kuò)展上面的程序使它包括正方形面積的計(jì)算,用戶只要輸入它一條邊的長(zhǎng)度就可以了。做這個(gè)練習(xí)之前你需要了解一件事:如果你有兩個(gè)以上的選擇,你可以象這樣寫:
這里的elif是意思為“else if”的神秘代碼:)。所以,如foo等于1,做某件事;否則,如果foo等于2,那么做另外的一些事,等等。你也可以在程序中加入其它的選項(xiàng)--象三角形以及任意多邊形。隨你的便。
6. 循環(huán)
順序執(zhí)行和條件執(zhí)行僅僅是程序設(shè)計(jì)三個(gè)基本語句塊架構(gòu)方式中的兩個(gè)。第三個(gè)則是循環(huán)執(zhí)行。在上個(gè)段落中我假設(shè)了一種情況,檢查火腿是否燒好,但很明顯它并不適用。如果下次檢查時(shí)火腿仍然沒燒好該怎么辦?我們?cè)趺粗佬枰獧z查多少次?事實(shí)上,我們不知道。而且我們也沒必要知道。我們可以要求計(jì)算機(jī)持續(xù)檢查直到燒好了為止。怎么表達(dá)這個(gè)?你猜到了--我們使用循環(huán),或者說是重復(fù)執(zhí)行。
python有兩種循環(huán)類型:while循環(huán)和for循環(huán)。for循環(huán)大概是最簡(jiǎn)單的。舉個(gè)例子:
它的意思是:對(duì)于列表"spam", "eggs", "tomatoes"中的每個(gè)元素,都打印出你喜歡它。循環(huán)中的語句塊為每個(gè)元素執(zhí)行一次,而且每次執(zhí)行,當(dāng)前的元素都被賦給變量food(在這個(gè)例子中)。另外一個(gè)例子:
函數(shù)range返回給定范圍的數(shù)字列表(包括第一個(gè)數(shù)字,不包括最后一個(gè)……這個(gè)例子中是[1……99])。所以,這樣解釋它:
循環(huán)體為1(包括)到100(不包括)之間的數(shù)字每個(gè)執(zhí)行一次。(哪個(gè)是循環(huán)體以及隨后的表達(dá)式事實(shí)上做什么留下來做為練習(xí)。)
但這對(duì)我們的燒菜問題并沒有實(shí)質(zhì)的幫助。如果我們打算檢查火腿一百次,那么這是個(gè)很好的解決方案;但是我們不知道這是否夠--或者太多了。我們只是希望它在溫度達(dá)不到(或者,直到它足夠熱--大致某個(gè)狀態(tài))的時(shí)候持續(xù)檢查。所以,我們使用while:
這個(gè)例子中的新東西……
1. 有些有用的函數(shù)被存儲(chǔ)在模塊中而且可以被導(dǎo)入。此例中我們從python自帶的time模塊中導(dǎo)入了函數(shù)sleep(它休止給定的多少秒的時(shí)間)。(做你自己的模塊當(dāng)然也是可能的……)
練習(xí)2:
寫一個(gè)程序,持續(xù)從用戶獲得數(shù)據(jù)然后相加,直到它們的和為100。再寫一個(gè)程序,從用戶那里獲得100個(gè)數(shù)據(jù),打印出它們的和。
Bigger Programs - Abstraction
如果想知道一本書的大致內(nèi)容,你不會(huì)翻遍所有的頁--你只是看看目錄,是不是?它會(huì)列出書的主要內(nèi)容?,F(xiàn)在--想像寫一本菜譜。許多菜譜,像“奶油火腿通心面”和“瑞士火腿餡餅”很可能包含相同的東西,比如火腿,在這種情況下--你肯定不會(huì)打算在每個(gè)菜譜里都重復(fù)敘述如何制作火腿。(好了……你事實(shí)上可能不做火腿……但是為了做例子,請(qǐng)忍受一下:))。你會(huì)把制作火腿的菜譜單獨(dú)放在一個(gè)章節(jié),而僅僅在其它章節(jié)里引用它。這樣--代替在每個(gè)菜譜里都完整的描述,你只要引用章節(jié)的名稱就可以了。在計(jì)算機(jī)編程中這被稱為抽象化。
我們是不是已經(jīng)象這樣運(yùn)行了某些東西?是的。我們沒有詳細(xì)的告訴計(jì)算機(jī)如何從用戶那里獲得一個(gè)答案(好了--我們沒有真的這樣做……同樣地……我們也沒有真正的在做火腿:))而是簡(jiǎn)單的使用了input--一個(gè)函數(shù)來代替。我們事實(shí)上可以構(gòu)造我們自己的函數(shù),來應(yīng)用于這種類型的抽象化中。
假設(shè)我們希望找到小于給定正數(shù)的最大整數(shù)。例如,給定2.7,這個(gè)數(shù)應(yīng)當(dāng)是2。這往往被稱為給定數(shù)的“底線(floor)”。(這事實(shí)上可以用python的內(nèi)建函數(shù)int來處理,但是,請(qǐng)?jiān)俅稳淌芪夷盟骼印┪覀冊(cè)撛鯓幼觯恳粋€(gè)簡(jiǎn)單的解決辦法是從0開始試每一個(gè)可能的數(shù):
注意當(dāng)floor不再小于(或者等于)給定數(shù)時(shí)循環(huán)結(jié)束了;我們加了太多1給它。因此我們必須為它減去1。如果我們希望把它應(yīng)用于完整的數(shù)學(xué)運(yùn)算該怎么辦呢?我們不得不為求每個(gè)數(shù)的基數(shù)("floor"-ing)而寫一次完整的循環(huán)。這很不舒服……你可能猜到了我們代之以什么:把它放在我們自己的函數(shù)中,命名為“floor”:
這個(gè)例子中的新東西……
1. 函數(shù)用關(guān)鍵字def定義,函數(shù)名緊隨其后并且要用括號(hào)把需要的參數(shù)括起來。
2. 如果要求函數(shù)返回一個(gè)值,要使用關(guān)鍵字return來處理(它同時(shí)也自動(dòng)結(jié)束函數(shù)定義)。
定義了函數(shù)之后,我們可以象這樣使用它:
執(zhí)行后,y的值應(yīng)該是2。定義擁有多個(gè)參數(shù)的函數(shù)也是可以的:
練習(xí)3
寫一個(gè)函數(shù),用歐幾里德方法尋找兩個(gè)數(shù)的一個(gè)共同因數(shù)。工作過程是這樣的:
1. 假設(shè)兩個(gè)數(shù),a和b,a大于b
2. 重復(fù)以下步驟直到b變成0:
1. a變?yōu)閎的值
2. b變成沒有改變值之前的a除以沒有改變值之前的b的余數(shù)
3. 返回a的最后一個(gè)值
提示:
* 使用a和b作為函數(shù)的參數(shù)
* 簡(jiǎn)單的設(shè)定a大于b
* x除以z的余數(shù)用表達(dá)式 x % z 來計(jì)算
* 兩個(gè)變量可以象這樣一起賦值:x, y = y, y+1。這里x被賦以值y(這意味著,y的值此前已經(jīng)指定)而且y被遞增了1。
7. 深入函數(shù)
上面的練習(xí)怎么做?難嗎?還不太清楚函數(shù)?別擔(dān)心--我還沒完成我的話題呢。
我們構(gòu)建函數(shù)時(shí)使用的萃取方法稱為過程抽象,許多編程語言把關(guān)鍵字過程同函數(shù)一樣使用。事實(shí)上,這兩個(gè)概念是不一樣的,但是在python中它們都被稱為函數(shù)(因?yàn)樗鼈兓蚨嗷蛏僖酝瑯拥姆绞蕉x和使用)。
函數(shù)和過程(在其它語言中)的區(qū)別在哪里呢?嗯--就像你在前面的段落里看到的那樣,函數(shù)可以返回一個(gè)值。區(qū)別就是過程并不返回這樣的值。許多時(shí)候,用這種方法把函數(shù)劃分為兩種類型--返回值的和不返回值的--是很有用的。
不返回值的函數(shù)(過程)可以用作子程序或例行程序。我們調(diào)用這些函數(shù),它們制造某些原料,就象泡沫鮮奶之類的。我們可以在很多地方使用這個(gè)函數(shù)而不需要重寫它的代碼(這被稱為代碼再利用--以后你還會(huì)知道,它意義不僅僅在這里)。
這樣的函數(shù)(或過程)的另一個(gè)有用性體現(xiàn)在--它改變了環(huán)境(例如,把糖和奶油混在一起攪拌,它們的整個(gè)外部狀態(tài)就變化了)讓我們看個(gè)例子:
打印出內(nèi)容是它一方面的作用,因?yàn)檫@是這個(gè)函數(shù)唯一需要做的事,它其實(shí)是一個(gè)典型的所謂過程。但是……它事實(shí)上沒有改變它的運(yùn)行環(huán)境,是不是?它怎樣才能改變呢?讓我們?cè)囈幌拢?
錯(cuò)在哪兒?錯(cuò)在函數(shù)setAge創(chuàng)建了它自己的也被命名為age的局部變量,它只在setAge函數(shù)內(nèi)部可用。那如何才可以避免出現(xiàn)這個(gè)問題呢?我們可以使用全局變量。
注意:全局變量在python中不常用。它們?nèi)菀滓鸩缓玫拇a組織結(jié)構(gòu),被稱為意大利面代碼。我這里使用它們是為了引出更復(fù)雜一點(diǎn)的技術(shù)問題--如果你可以請(qǐng)盡量避免使用它們。
[color=#FF0000]未譯完。。。[/color]
rockety 回復(fù)于:2005-06-06 09:27:59
[color=red]譯完了的,只是不小心,沒在我的blog上貼全,而且也沒有給出縮進(jìn)。:oops: 今天一并更正了。感謝wolfg轉(zhuǎn)貼,并給出了正確的縮進(jìn)。以下是其余部分:[/color]
通過告訴解釋器一個(gè)變量是全局的(用象global age這樣的表達(dá)式做),我們事實(shí)上
告訴了它在函數(shù)之外使用這個(gè)變量,而不是重新創(chuàng)建一個(gè)新的局部變量。(所以,和局部
相反它是全局的。)因此上面的程序可以象這樣重寫:
了解對(duì)象(隨后談到)后,你會(huì)發(fā)現(xiàn)更好的解決這個(gè)問題的辦法是使用一個(gè)有age屬
性和setAge方法的對(duì)象。在數(shù)據(jù)結(jié)構(gòu)那段,你也將會(huì)發(fā)現(xiàn)一些函數(shù)改變它的環(huán)境的更好的
例子。
好了--那么真正的函數(shù)是什么樣?什么是函數(shù)呢,事實(shí)上?數(shù)學(xué)函數(shù)象一種“機(jī)
器”,獲得輸入然后計(jì)算結(jié)果。它會(huì)每次返回同樣的結(jié)果,如果每次提供它同樣的輸入。
例如:
這和數(shù)學(xué)上的函數(shù)f(x)=x*x 一樣。它的行為象一個(gè)精確的函數(shù),僅僅依賴于它的輸
入,在任何情況下都不改變它的環(huán)境。
所以--我這里描繪了兩種構(gòu)造函數(shù)的方法:一種類型更象是過程,不返回任何結(jié)
果;另一種更象是數(shù)學(xué)上的函數(shù),(幾乎)什么也不做就是為了返回一個(gè)結(jié)果。當(dāng)然,在
這兩種極端事物之間做某些事情是可能的,盡管當(dāng)函數(shù)改變事物的時(shí)候,它應(yīng)該清楚它改
變了。你可以通過標(biāo)記它們的名字區(qū)分它們,例如為“純粹”的函數(shù)使用象square這樣的
名詞而對(duì)類似過程那樣的函數(shù)使用象setAge這樣命令式的名字。
9. 更多類型-數(shù)據(jù)結(jié)構(gòu)
現(xiàn)在--你已經(jīng)知道了不少:怎樣輸入輸出,怎樣設(shè)計(jì)復(fù)雜的運(yùn)算法則(程序)來執(zhí)
行數(shù)學(xué)運(yùn)算,但是好戲還在后頭呢。
截止目前我們都在程序中使用了哪些成份呢?數(shù)字和字符串,對(duì)不對(duì)?沒意思的種
類……現(xiàn)在讓我們引入兩三個(gè)其它的成份來讓事情變得更有意思些。
數(shù)據(jù)結(jié)構(gòu)是種組織數(shù)據(jù)的成份。(驚奇,吃驚……)單個(gè)的數(shù)據(jù)沒有什么真正的數(shù)據(jù)
結(jié)構(gòu),是不是?但是假設(shè)我們需要很多數(shù)放在一起做為一個(gè)成份--那就需要某種結(jié)構(gòu)。
例如,我們可能想要一個(gè)數(shù)據(jù)列表。那很容易:
[3, 6, 78, 93]
在循環(huán)那段我提到了列表,但沒真正描述它。好--這里說的就是你如何創(chuàng)建它。只
需要列出元素,用逗號(hào)分開,再加上方括號(hào)就行了。
來看一個(gè)計(jì)算素?cái)?shù)(只能被1和它本身整除的數(shù))的例子:
這個(gè)例子中的新東西……
內(nèi)建函數(shù)range事實(shí)上返回一個(gè)列表,可以象所有其它列表那樣使用。(它包括第
一個(gè)數(shù),但是不包括最后一個(gè)數(shù)。)
列表可以當(dāng)作邏輯變量使用。如果它非空,則為true,否則為false。因此,while
candidates意思是“while名稱為candidates的列表非空時(shí)”或者簡(jiǎn)單的說“while存
在candidates時(shí)”。
你可以用if someElement in somelist來檢查一個(gè)元素是否在列表中。
你可以用someList.remove(someElement)來刪除someList中的someElement。
你可以用someList.append(something)為一個(gè)列表添加元素。事實(shí)上,你也可以使
用“+”(象someList = someList+[something])。但是效率不是太高。
你可以通過在列表名之后加上用括號(hào)括起來的表示某元素位置的數(shù)字(很奇怪,列
表的第1個(gè)元素,位置是0)來獲得列表的某個(gè)元素。因此someList[3]是someList
列表的第四個(gè)元素(依次類推)。
你可以使用關(guān)鍵字del刪除變量。它也可以用來刪除列表中的元素(就象這里)。
因此del someList[0]刪除someList 列表中的第一個(gè)元素。如果刪除前列表是[1, 2,
3],刪除后就變成了[2, 3]。
在繼續(xù)敘述索引列表中的元素之前,我簡(jiǎn)單解釋一下上面的例子。
這是古老算術(shù)的一個(gè)版本,稱為“The Sieve of Erastothenes”(類似這樣)。它考量一
系列給定數(shù)字(在本例中是一個(gè)列表),然后有組織的刪除已知不是素?cái)?shù)的數(shù)字。如何知
道?只要看看它們是不是可以被分解為其它兩個(gè)數(shù)就可以了。
我們從一個(gè)包含數(shù)字[2...999]的候選列表開始--我們知道1是素?cái)?shù)(事實(shí)上,它可能
是也可能不是,看你問誰了),我們想得到小于1000的所有素?cái)?shù)。(事實(shí)上,我們的候
選列表是[3...999],但是2也是候選數(shù)字,因?yàn)樗俏覀兊牡谝粋€(gè)base)。我們還有個(gè)叫result的列表,它任何時(shí)間都包含著最新的結(jié)果。最初的時(shí)候,它只包含1。我們還有個(gè)叫base的變量。每次循環(huán),我們刪除是它的倍數(shù)的數(shù)字(它總是候選列表中最小的數(shù))。每次循環(huán)之后,我們知道剩下的最小的數(shù)是素?cái)?shù)(因?yàn)樗锌梢苑纸獾臄?shù)我們都刪除了)。
因此,我們把它加入result,并把它設(shè)為新的base,然后從列表里移除它(這樣就不會(huì)對(duì)
它重復(fù)計(jì)算了)。當(dāng)候選列表為空時(shí),result列表將包含所有的素?cái)?shù)。精巧吧,哈!
思考一下:第一次循環(huán)有什么特別嗎?那時(shí)base 是2,但它一樣經(jīng)過了篩選。為什
么?為什么這不發(fā)生在其它的base值身上?我們打算移除product時(shí)能否確定它在候選列
表中呢?為什么?
接下來是什么呢?哦,是的……索引。還有切片。它們是從python列表中獲得單個(gè)
元素的方法。你已經(jīng)見到了普通的索引行為。它相當(dāng)簡(jiǎn)單。事實(shí)上,我已經(jīng)告訴了你所有
你需要知道的關(guān)于它的東西,除了一件事:負(fù)數(shù)索引從列表的末尾向前計(jì)算。所以,
someList[-1]是someList的最后一個(gè)元素,someList[-2]是它之前的一個(gè)元素,依次類
推。
切片,仍然,對(duì)你來說是陌生的。它和索引相似,除了切片可以獲得列表中的所有的
元素,而不僅僅是單個(gè)的元素。這如何做呢?象這樣:
10. 繼續(xù)抽象-對(duì)象和面向?qū)ο缶幊?
現(xiàn)在有個(gè)比較熱門的詞叫做“面向?qū)ο缶幊獭薄?
就象本段標(biāo)題暗示的那樣,面向?qū)ο缶幊虄H僅是另外一種抽象細(xì)節(jié)的方式。程序通過
命名將簡(jiǎn)單的描述抽象為復(fù)雜的操作。在面向?qū)ο缶幊虝r(shí),我們不僅可以這樣對(duì)待程序,
還可以把它們做為對(duì)象。(現(xiàn)在,這肯定會(huì)讓你吃驚,哈?。├纾绻帉憻鹜瘸?
序,我們不用編寫很多過程來處理溫度、時(shí)間、成份等等,我們可以把它們結(jié)合為一個(gè)火
腿對(duì)象?;蛘撸苍S我們可以再有爐子對(duì)象和時(shí)鐘對(duì)象……那么,象溫度這類事物就變成
了火腿對(duì)象的一個(gè)屬性,而時(shí)間可以從時(shí)鐘對(duì)象讀取。要使用我們的程序做某些事,我們
可以教給我們的對(duì)象某些方法;比如,爐子應(yīng)當(dāng)知道如何烹制火腿等。
那么--在python中我們?nèi)绾巫瞿??我們不能直接制造一個(gè)對(duì)象。不能直接制造一個(gè)
爐子,而是做一個(gè)菜譜來描述爐子應(yīng)該是什么樣。這份菜譜因此就描述了一個(gè)被我們稱為
爐子的一類對(duì)象。一個(gè)非常簡(jiǎn)單的爐子類可能是這樣:
這看起來很難理解,還是怎樣呢?
這個(gè)例子中的新東西……
對(duì)象的類用關(guān)鍵字class定義。
類的名稱通常以大寫字母開始,而函數(shù)和變量(還有屬性和方法)的名稱以小寫字
母開始。
方法(也就是讓對(duì)象知道如何去做的函數(shù)和操作)的定義沒有特別,但是要在類的
定義里面。
所有對(duì)象的方法應(yīng)當(dāng)有的第一個(gè)參數(shù)叫做self(或者類似的……)原因很快就清楚
了。
對(duì)象的屬性和方法可以這樣來訪問:mySpam.temperature = 2 或者dilbert.be_nice
()。
我能猜到上面例子中的某些東西你仍然不清楚。例如,什么是self?還有,現(xiàn)在我們
有了對(duì)象菜譜(也就是類),我們?cè)鯓邮聦?shí)上構(gòu)造一個(gè)對(duì)象呢?
我們先顛倒一下順序。對(duì)象通過象引用函數(shù)那樣引用類名來創(chuàng)建:
myOven包含了一個(gè)Oven對(duì)象,通常叫做Oven類的一個(gè)實(shí)例。假設(shè)我們也構(gòu)造好了
一個(gè)Spam類,那么我們可象這樣做:
myOven.spam現(xiàn)在將包含mySpam。怎么回事?因?yàn)?,我們調(diào)用一個(gè)對(duì)象的某個(gè)方法
時(shí),第一個(gè)參數(shù),通常稱為self,總是包含對(duì)象本身。(巧妙,哈?。┻@樣,self.spam =spam這一行設(shè)置當(dāng)前Oven對(duì)象的spam屬性的值為參數(shù)spam。注意它們是兩個(gè)不同的事物,盡管在這個(gè)例子中它們都被稱為spam。
11. 練習(xí)3答案
這是這個(gè)運(yùn)算法則的一個(gè)非常簡(jiǎn)潔的版本:
12. 參考
[1]假日火腿沙拉菜譜摘自獺ormel Foods壞繾影娌似住?
Copyright ?nbsp;Magnus Lie Hetland 肯定來過[譯]
Instant Hacking[譯文]
譯者: 肯定來過
這是一篇簡(jiǎn)短的關(guān)于python程序設(shè)計(jì)語言的入門教程,原文在這里,翻著詞典翻譯了來!
這是一份對(duì)編程藝術(shù)的簡(jiǎn)短介紹,其中的例子是用python寫成的。(如果你已經(jīng)知道了該如何編程,但是想簡(jiǎn)單了解一下python,你可以查閱我的另一篇文章Instant Python。)這篇文章已經(jīng)被翻譯為意大利、波蘭、日本、塞爾維亞以及巴西葡萄亞語等許多種語言,而且正在被翻譯為韓語。(譯者:當(dāng)然,現(xiàn)在已經(jīng)包括了中文版本,只是作者并不知道。)
這篇文章和如何闖入別人的計(jì)算機(jī)系統(tǒng)之類的東西無關(guān)。我不關(guān)注那類事情,所以請(qǐng)不要email問我那些東西。
注意:要使此文中的例子正確運(yùn)行,你應(yīng)該把它們寫在一個(gè)文本文件中,然后用解釋器運(yùn)行;不要試圖直接在交互方式下運(yùn)行它們--不是所有的都可以這樣運(yùn)行。(不要問我和此有關(guān)的具體細(xì)節(jié)。最好查閱python文檔或者email給help@python.org)。
1. 運(yùn)行環(huán)境
要用python寫程序,你必須先安裝一個(gè)python的解釋器。它可以存在于大多數(shù)平臺(tái)(包括Macintosh、Unix和Windows)。更多與此有關(guān)的信息可以在python的網(wǎng)站上找到。你還應(yīng)該有一個(gè)文本編輯器(象emacs、notepad或者類似的東西)。
2. 編程是什么?
為計(jì)算機(jī)寫程序其實(shí)就是給它一系列的指令告訴它去做什么。計(jì)算機(jī)程序在某些方面就象是菜譜,指導(dǎo)我們?nèi)绾巫霾说哪欠N。例如[1]:
假日火腿沙拉
原料:
腌泡汁:
1/4杯酸橙汁
1/4杯低鈉大豆醬油
1/4杯水
1大湯匙植物油
3/4茶匙小茴香
1/2茶匙牛至
1/4茶匙熱胡椒粉
2片丁香、大蒜,搗碎
沙拉:
1份(12盎司)罐裝少鈉午餐肉火腿切成條狀
1個(gè)洋蔥,切片
胡椒粉,切好的生菜
12個(gè)櫻桃西紅柿,切半
方法:
把腌泡汁裝在有合適蓋子的廣口瓶里搖勻。用塑料袋裝上火腿,潑上腌泡汁,封住袋口。在電冰箱里腌制30分鐘。從塑料袋里取出火腿;準(zhǔn)備2大湯匙腌泡汁,在煮鍋里煮一下。加上火腿、洋蔥、綠色的胡椒。燒3到4分鐘直到火腿熟了為止……
當(dāng)然,沒有一臺(tái)計(jì)算機(jī)會(huì)懂這個(gè)……而且即便是懂,大多數(shù)計(jì)算機(jī)也不可能燒制出一份沙拉。那么,我們?cè)撊绾巫屵@些變得對(duì)計(jì)算機(jī)來說更為友好一些呢?從根本上說依賴于兩點(diǎn):首先,我們必須以計(jì)算機(jī)可以理解的方式與之交流;其次還要和它談?wù)撍軌蜃龅降氖虑椤?
第一點(diǎn)意味著我們必須使用一種語言--一種已經(jīng)為之準(zhǔn)備好了解釋器的程序設(shè)計(jì)語言,第二點(diǎn)意味著我們不能期望計(jì)算機(jī)為我們做一份沙拉--但是我們可以讓它做數(shù)字累加或者在屏幕上打印東西之類的事情。
3. Hello……
程序設(shè)計(jì)教程有一個(gè)傳統(tǒng),通常以在屏幕上打印“Hello, world!”這樣的程序做為開始。對(duì)python來說,這非常簡(jiǎn)單:
print "Hello, world!"
它從根本上說很象上面的菜譜(盡管要短得多?。?。它告訴計(jì)算機(jī)做什么:打印“Hello, world!”。如果讓它打印更多的廢話該怎么做呢?很簡(jiǎn)單:
print "Hello, world!"
print "Goodbye, world!"
不比上一個(gè)難,是不是?但是不怎么有趣……我們希望它可以處理更多的元素,就象沙拉菜譜那樣。那么,我們都有哪些元素呢?首先,有字符串,象“Hello, world!”,除此之外還有數(shù)字。假設(shè)我們打算讓計(jì)算機(jī)為我們計(jì)算矩形的面積。我們可以給它如下的菜譜:
# The Area of a Rectangle
# Ingredients:
width = 20
height = 30
# Instructions:
area = width * height
print area
你大概可以看出它同火腿沙拉菜譜的相似性(盡管有些細(xì)微的差別)。但它是如何工作的呢?首先,以#開始的行叫做注釋事實(shí)上會(huì)被計(jì)算機(jī)忽略。然而插入象這樣小段的注釋對(duì)于增強(qiáng)你程序的可讀性來說是很重要的。
接下來,看起來象 foo = bar 這樣的行叫做賦值。對(duì)于 width = 20 這樣的情況來說就是告訴計(jì)算機(jī)從這里開始width就代表20了。它還意味著一個(gè)名字為“width”的變量從此被創(chuàng)建了(如果它先前已經(jīng)存在,那么會(huì)被重新覆蓋)。所以,我們以后使用這個(gè)變量的時(shí)候,計(jì)算機(jī)就知道了它的值。因此,
width * height
本質(zhì)上同
20 * 30
一樣會(huì)計(jì)算出600這個(gè)結(jié)果,然后賦給名稱為“area”的變量。程序的最后一句在屏幕上打印出變量“area”的值,所以你看到這個(gè)程序運(yùn)行的最終結(jié)果僅僅是
600
注意:在某些程序設(shè)計(jì)語言中,你必須在程序開始的時(shí)候告訴計(jì)算機(jī)你將會(huì)用到哪些變量(就象沙拉中的元素)--而python足夠聰明,所以你可以根據(jù)需要隨時(shí)創(chuàng)建。
4. 反饋
現(xiàn)在,你可以執(zhí)行一些簡(jiǎn)單,或者再?gòu)?fù)雜一點(diǎn)的計(jì)算了。比方說,你或許打算寫一段程序來計(jì)算圓形的面積而不是矩形的:
radius = 30
print radius * radius * 3.14
然而,這事實(shí)上并不比計(jì)算矩形面積的那個(gè)程序更有意思。至少在我看來是這樣。它有些僵硬。如果我們看到半徑為31的圓該怎么辦?怎樣讓計(jì)算機(jī)知道?這有點(diǎn)象沙拉菜譜中的:“燒3到4分鐘直到火腿熟了為止。”要知道何時(shí)燒熟,我們必須檢查。我們需要反饋,或者提示。計(jì)算機(jī)如何知道我們圓形的半徑?同樣需要輸入資料……我們可以做的是告訴計(jì)算機(jī)半徑是多少:
radius = input("What is the radius?")
print radius * radius * 3.14
現(xiàn)在程序變得漂亮一些了……input是個(gè)被稱為函數(shù)的東西。(很快你將學(xué)習(xí)創(chuàng)建你自己的函數(shù)。而input是python內(nèi)建的函數(shù)。)僅僅寫下
input
什么也不會(huì)做……你必須在它的后面放上一對(duì)括號(hào)。所以input()可以工作--它會(huì)簡(jiǎn)單的要求用戶輸入半徑的長(zhǎng)度。而上面的那個(gè)版本對(duì)用戶來說也許更友好一些,因?yàn)樗紫却蛴〕隽艘粋€(gè)問題。當(dāng)我們將諸如提問字符串“What is the radius?”之類的東西放在函數(shù)調(diào)用的括號(hào)中時(shí),這個(gè)過程被稱為函數(shù)的參數(shù)傳遞。括號(hào)中的內(nèi)容被稱為參數(shù)。在上個(gè)例子中我們傳遞了一個(gè)提問作為參數(shù)以便input知道在獲得答案前應(yīng)該先打印什么。
但是獲得的答案如何到達(dá)radius變量呢?函數(shù)input,調(diào)用時(shí),會(huì)返回一個(gè)值(象許多其它函數(shù)一樣)。你不一定非要使用這個(gè)值,但象我們這種情況,我們要使用它。這樣,下面這兩個(gè)表達(dá)式有著很大的差別:
foo = input
bar = input()
foo現(xiàn)在包含input函數(shù)本身(所以它事實(shí)上可以象foo("What is your age?")這樣使用;這被稱為動(dòng)態(tài)函數(shù)調(diào)用)而bar包含用戶鍵入的值。
5. 流程
現(xiàn)在我們可以編寫程序執(zhí)行簡(jiǎn)單的任務(wù)(運(yùn)算和打?。┎⑶铱梢垣@得用戶輸入了。這很有用,但仍然局限在按順序執(zhí)行命令,也就是說--它們必須按照事先安排好的順序執(zhí)行。大多數(shù)火腿沙拉菜譜是象這樣順序或者線性敘述的。但是如果我們打算讓計(jì)算機(jī)檢查沙拉是否燒好該怎樣告訴它呢?如果燒好了,那么應(yīng)該從烘箱里把它取出來--否則的話,應(yīng)該接著讓它燒更長(zhǎng)一段時(shí)間什么的。我們?nèi)绾伪磉_(dá)這個(gè)?
我們想做的,其實(shí)是控制程序的流程。它可以從兩個(gè)方向執(zhí)行--要么拿開火腿,要不繼續(xù)讓它留在烘箱里。我們可以選擇,條件是它是否燒好。這被稱為條件執(zhí)行。我們可以這樣寫:
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(攝氏度),那么打印出信息告訴用戶燒好了,否則,告訴用戶再燒制一段時(shí)間。
注意:縮進(jìn)在python中很重要。條件執(zhí)行(還有循環(huán)執(zhí)行以及函數(shù)定義--見后面)中的語句塊必須被縮進(jìn)(而且要縮進(jìn)同等數(shù)量的空格;一個(gè)鍵相當(dāng)于8個(gè)空格)以便解釋器可以知道它們從哪里開始到哪里結(jié)束。這同時(shí)也使程序變得更加可讀。
讓我們回到先前的面積計(jì)算問題。能看出來這段程序做什么嗎?
# Area calculation program
print "Welcome to the Area calculation program"
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
這個(gè)例子中的新東西:
1. 只使用print本身將打印出一個(gè)空行
2. ==檢查兩個(gè)值是否相等,與=不同,后者把表達(dá)式右側(cè)的值賦給左側(cè)的變量。這是一個(gè)非常重要的差別!
3. **是python的冪運(yùn)算符--因此半徑的平方被寫成radius**2
4. print能夠打印出不止一個(gè)東西。只要用逗號(hào)把它們分開就可以了。(它們?cè)谳敵鰰r(shí)會(huì)用單個(gè)空格分開。)
這個(gè)程序很簡(jiǎn)單:它要一個(gè)數(shù)字,告訴它用戶打算讓它計(jì)算矩形或是圓形的面積。然后,使用一個(gè)if語句(條件執(zhí)行)來決定應(yīng)當(dāng)執(zhí)行哪個(gè)語句塊計(jì)算面積。這兩個(gè)語句塊同先前面積計(jì)算例子中使用的語句塊本質(zhì)上是一樣的。留意注釋是如何使代碼變得更加可讀的。編程的第一條戒律就是:“你應(yīng)當(dāng)注釋!”無論如何--它都是一個(gè)應(yīng)該養(yǎng)成的好習(xí)慣。
練習(xí)1:
擴(kuò)展上面的程序使它包括正方形面積的計(jì)算,用戶只要輸入它一條邊的長(zhǎng)度就可以了。做這個(gè)練習(xí)之前你需要了解一件事:如果你有兩個(gè)以上的選擇,你可以象這樣寫:
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,那么做另外的一些事,等等。你也可以在程序中加入其它的選項(xiàng)--象三角形以及任意多邊形。隨你的便。
6. 循環(huán)
順序執(zhí)行和條件執(zhí)行僅僅是程序設(shè)計(jì)三個(gè)基本語句塊架構(gòu)方式中的兩個(gè)。第三個(gè)則是循環(huán)執(zhí)行。在上個(gè)段落中我假設(shè)了一種情況,檢查火腿是否燒好,但很明顯它并不適用。如果下次檢查時(shí)火腿仍然沒燒好該怎么辦?我們?cè)趺粗佬枰獧z查多少次?事實(shí)上,我們不知道。而且我們也沒必要知道。我們可以要求計(jì)算機(jī)持續(xù)檢查直到燒好了為止。怎么表達(dá)這個(gè)?你猜到了--我們使用循環(huán),或者說是重復(fù)執(zhí)行。
python有兩種循環(huán)類型:while循環(huán)和for循環(huán)。for循環(huán)大概是最簡(jiǎn)單的。舉個(gè)例子:
for food in "spam", "eggs", "tomatoes":
print "I love", food
它的意思是:對(duì)于列表"spam", "eggs", "tomatoes"中的每個(gè)元素,都打印出你喜歡它。循環(huán)中的語句塊為每個(gè)元素執(zhí)行一次,而且每次執(zhí)行,當(dāng)前的元素都被賦給變量food(在這個(gè)例子中)。另外一個(gè)例子:
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!"
函數(shù)range返回給定范圍的數(shù)字列表(包括第一個(gè)數(shù)字,不包括最后一個(gè)……這個(gè)例子中是[1……99])。所以,這樣解釋它:
循環(huán)體為1(包括)到100(不包括)之間的數(shù)字每個(gè)執(zhí)行一次。(哪個(gè)是循環(huán)體以及隨后的表達(dá)式事實(shí)上做什么留下來做為練習(xí)。)
但這對(duì)我們的燒菜問題并沒有實(shí)質(zhì)的幫助。如果我們打算檢查火腿一百次,那么這是個(gè)很好的解決方案;但是我們不知道這是否夠--或者太多了。我們只是希望它在溫度達(dá)不到(或者,直到它足夠熱--大致某個(gè)狀態(tài))的時(shí)候持續(xù)檢查。所以,我們使用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!"
這個(gè)例子中的新東西……
1. 有些有用的函數(shù)被存儲(chǔ)在模塊中而且可以被導(dǎo)入。此例中我們從python自帶的time模塊中導(dǎo)入了函數(shù)sleep(它休止給定的多少秒的時(shí)間)。(做你自己的模塊當(dāng)然也是可能的……)
練習(xí)2:
寫一個(gè)程序,持續(xù)從用戶獲得數(shù)據(jù)然后相加,直到它們的和為100。再寫一個(gè)程序,從用戶那里獲得100個(gè)數(shù)據(jù),打印出它們的和。
Bigger Programs - Abstraction
如果想知道一本書的大致內(nèi)容,你不會(huì)翻遍所有的頁--你只是看看目錄,是不是?它會(huì)列出書的主要內(nèi)容?,F(xiàn)在--想像寫一本菜譜。許多菜譜,像“奶油火腿通心面”和“瑞士火腿餡餅”很可能包含相同的東西,比如火腿,在這種情況下--你肯定不會(huì)打算在每個(gè)菜譜里都重復(fù)敘述如何制作火腿。(好了……你事實(shí)上可能不做火腿……但是為了做例子,請(qǐng)忍受一下:))。你會(huì)把制作火腿的菜譜單獨(dú)放在一個(gè)章節(jié),而僅僅在其它章節(jié)里引用它。這樣--代替在每個(gè)菜譜里都完整的描述,你只要引用章節(jié)的名稱就可以了。在計(jì)算機(jī)編程中這被稱為抽象化。
我們是不是已經(jīng)象這樣運(yùn)行了某些東西?是的。我們沒有詳細(xì)的告訴計(jì)算機(jī)如何從用戶那里獲得一個(gè)答案(好了--我們沒有真的這樣做……同樣地……我們也沒有真正的在做火腿:))而是簡(jiǎn)單的使用了input--一個(gè)函數(shù)來代替。我們事實(shí)上可以構(gòu)造我們自己的函數(shù),來應(yīng)用于這種類型的抽象化中。
假設(shè)我們希望找到小于給定正數(shù)的最大整數(shù)。例如,給定2.7,這個(gè)數(shù)應(yīng)當(dāng)是2。這往往被稱為給定數(shù)的“底線(floor)”。(這事實(shí)上可以用python的內(nèi)建函數(shù)int來處理,但是,請(qǐng)?jiān)俅稳淌芪夷盟骼印┪覀冊(cè)撛鯓幼觯恳粋€(gè)簡(jiǎn)單的解決辦法是從0開始試每一個(gè)可能的數(shù):
number = input("What is the number?")
floor = 0
while floor <= number:
floor = floor + 1
floor = floor - 1
print "The floor of ", number, "is ", floor
注意當(dāng)floor不再小于(或者等于)給定數(shù)時(shí)循環(huán)結(jié)束了;我們加了太多1給它。因此我們必須為它減去1。如果我們希望把它應(yīng)用于完整的數(shù)學(xué)運(yùn)算該怎么辦呢?我們不得不為求每個(gè)數(shù)的基數(shù)("floor"-ing)而寫一次完整的循環(huán)。這很不舒服……你可能猜到了我們代之以什么:把它放在我們自己的函數(shù)中,命名為“floor”:
def floor(number):
result = 0
while result <= number:
result = result + 1
result = result - 1
return result
這個(gè)例子中的新東西……
1. 函數(shù)用關(guān)鍵字def定義,函數(shù)名緊隨其后并且要用括號(hào)把需要的參數(shù)括起來。
2. 如果要求函數(shù)返回一個(gè)值,要使用關(guān)鍵字return來處理(它同時(shí)也自動(dòng)結(jié)束函數(shù)定義)。
定義了函數(shù)之后,我們可以象這樣使用它:
x = 2.7
y = floor(2.7)
執(zhí)行后,y的值應(yīng)該是2。定義擁有多個(gè)參數(shù)的函數(shù)也是可以的:
def sum(x, y):
return x + y
練習(xí)3
寫一個(gè)函數(shù),用歐幾里德方法尋找兩個(gè)數(shù)的一個(gè)共同因數(shù)。工作過程是這樣的:
1. 假設(shè)兩個(gè)數(shù),a和b,a大于b
2. 重復(fù)以下步驟直到b變成0:
1. a變?yōu)閎的值
2. b變成沒有改變值之前的a除以沒有改變值之前的b的余數(shù)
3. 返回a的最后一個(gè)值
提示:
* 使用a和b作為函數(shù)的參數(shù)
* 簡(jiǎn)單的設(shè)定a大于b
* x除以z的余數(shù)用表達(dá)式 x % z 來計(jì)算
* 兩個(gè)變量可以象這樣一起賦值:x, y = y, y+1。這里x被賦以值y(這意味著,y的值此前已經(jīng)指定)而且y被遞增了1。
7. 深入函數(shù)
上面的練習(xí)怎么做?難嗎?還不太清楚函數(shù)?別擔(dān)心--我還沒完成我的話題呢。
我們構(gòu)建函數(shù)時(shí)使用的萃取方法稱為過程抽象,許多編程語言把關(guān)鍵字過程同函數(shù)一樣使用。事實(shí)上,這兩個(gè)概念是不一樣的,但是在python中它們都被稱為函數(shù)(因?yàn)樗鼈兓蚨嗷蛏僖酝瑯拥姆绞蕉x和使用)。
函數(shù)和過程(在其它語言中)的區(qū)別在哪里呢?嗯--就像你在前面的段落里看到的那樣,函數(shù)可以返回一個(gè)值。區(qū)別就是過程并不返回這樣的值。許多時(shí)候,用這種方法把函數(shù)劃分為兩種類型--返回值的和不返回值的--是很有用的。
不返回值的函數(shù)(過程)可以用作子程序或例行程序。我們調(diào)用這些函數(shù),它們制造某些原料,就象泡沫鮮奶之類的。我們可以在很多地方使用這個(gè)函數(shù)而不需要重寫它的代碼(這被稱為代碼再利用--以后你還會(huì)知道,它意義不僅僅在這里)。
這樣的函數(shù)(或過程)的另一個(gè)有用性體現(xiàn)在--它改變了環(huán)境(例如,把糖和奶油混在一起攪拌,它們的整個(gè)外部狀態(tài)就變化了)讓我們看個(gè)例子:
def hello(who):
print "Hello, ", who
hello("world")
# Prints out "Hello, world"
打印出內(nèi)容是它一方面的作用,因?yàn)檫@是這個(gè)函數(shù)唯一需要做的事,它其實(shí)是一個(gè)典型的所謂過程。但是……它事實(shí)上沒有改變它的運(yùn)行環(huán)境,是不是?它怎樣才能改變呢?讓我們?cè)囈幌拢?
# The *wrong* way of doing it
age = 0
def setAge(a):
age = a
setAge(100)
print age
# Prints "0"
錯(cuò)在哪兒?錯(cuò)在函數(shù)setAge創(chuàng)建了它自己的也被命名為age的局部變量,它只在setAge函數(shù)內(nèi)部可用。那如何才可以避免出現(xiàn)這個(gè)問題呢?我們可以使用全局變量。
注意:全局變量在python中不常用。它們?nèi)菀滓鸩缓玫拇a組織結(jié)構(gòu),被稱為意大利面代碼。我這里使用它們是為了引出更復(fù)雜一點(diǎn)的技術(shù)問題--如果你可以請(qǐng)盡量避免使用它們。
[color=#FF0000]未譯完。。。[/color]
rockety 回復(fù)于:2005-06-06 09:27:59
[color=red]譯完了的,只是不小心,沒在我的blog上貼全,而且也沒有給出縮進(jìn)。:oops: 今天一并更正了。感謝wolfg轉(zhuǎn)貼,并給出了正確的縮進(jìn)。以下是其余部分:[/color]
通過告訴解釋器一個(gè)變量是全局的(用象global age這樣的表達(dá)式做),我們事實(shí)上
告訴了它在函數(shù)之外使用這個(gè)變量,而不是重新創(chuàng)建一個(gè)新的局部變量。(所以,和局部
相反它是全局的。)因此上面的程序可以象這樣重寫:
# The correct, but not-so-good way of doing it
age=0
def setAge(a):
global age
setAge(100)
print age
# Prints "100"
了解對(duì)象(隨后談到)后,你會(huì)發(fā)現(xiàn)更好的解決這個(gè)問題的辦法是使用一個(gè)有age屬
性和setAge方法的對(duì)象。在數(shù)據(jù)結(jié)構(gòu)那段,你也將會(huì)發(fā)現(xiàn)一些函數(shù)改變它的環(huán)境的更好的
例子。
好了--那么真正的函數(shù)是什么樣?什么是函數(shù)呢,事實(shí)上?數(shù)學(xué)函數(shù)象一種“機(jī)
器”,獲得輸入然后計(jì)算結(jié)果。它會(huì)每次返回同樣的結(jié)果,如果每次提供它同樣的輸入。
例如:
def square(x):
return x*x
這和數(shù)學(xué)上的函數(shù)f(x)=x*x 一樣。它的行為象一個(gè)精確的函數(shù),僅僅依賴于它的輸
入,在任何情況下都不改變它的環(huán)境。
所以--我這里描繪了兩種構(gòu)造函數(shù)的方法:一種類型更象是過程,不返回任何結(jié)
果;另一種更象是數(shù)學(xué)上的函數(shù),(幾乎)什么也不做就是為了返回一個(gè)結(jié)果。當(dāng)然,在
這兩種極端事物之間做某些事情是可能的,盡管當(dāng)函數(shù)改變事物的時(shí)候,它應(yīng)該清楚它改
變了。你可以通過標(biāo)記它們的名字區(qū)分它們,例如為“純粹”的函數(shù)使用象square這樣的
名詞而對(duì)類似過程那樣的函數(shù)使用象setAge這樣命令式的名字。
9. 更多類型-數(shù)據(jù)結(jié)構(gòu)
現(xiàn)在--你已經(jīng)知道了不少:怎樣輸入輸出,怎樣設(shè)計(jì)復(fù)雜的運(yùn)算法則(程序)來執(zhí)
行數(shù)學(xué)運(yùn)算,但是好戲還在后頭呢。
截止目前我們都在程序中使用了哪些成份呢?數(shù)字和字符串,對(duì)不對(duì)?沒意思的種
類……現(xiàn)在讓我們引入兩三個(gè)其它的成份來讓事情變得更有意思些。
數(shù)據(jù)結(jié)構(gòu)是種組織數(shù)據(jù)的成份。(驚奇,吃驚……)單個(gè)的數(shù)據(jù)沒有什么真正的數(shù)據(jù)
結(jié)構(gòu),是不是?但是假設(shè)我們需要很多數(shù)放在一起做為一個(gè)成份--那就需要某種結(jié)構(gòu)。
例如,我們可能想要一個(gè)數(shù)據(jù)列表。那很容易:
[3, 6, 78, 93]
在循環(huán)那段我提到了列表,但沒真正描述它。好--這里說的就是你如何創(chuàng)建它。只
需要列出元素,用逗號(hào)分開,再加上方括號(hào)就行了。
來看一個(gè)計(jì)算素?cái)?shù)(只能被1和它本身整除的數(shù))的例子:
# 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
這個(gè)例子中的新東西……
內(nèi)建函數(shù)range事實(shí)上返回一個(gè)列表,可以象所有其它列表那樣使用。(它包括第
一個(gè)數(shù),但是不包括最后一個(gè)數(shù)。)
列表可以當(dāng)作邏輯變量使用。如果它非空,則為true,否則為false。因此,while
candidates意思是“while名稱為candidates的列表非空時(shí)”或者簡(jiǎn)單的說“while存
在candidates時(shí)”。
你可以用if someElement in somelist來檢查一個(gè)元素是否在列表中。
你可以用someList.remove(someElement)來刪除someList中的someElement。
你可以用someList.append(something)為一個(gè)列表添加元素。事實(shí)上,你也可以使
用“+”(象someList = someList+[something])。但是效率不是太高。
你可以通過在列表名之后加上用括號(hào)括起來的表示某元素位置的數(shù)字(很奇怪,列
表的第1個(gè)元素,位置是0)來獲得列表的某個(gè)元素。因此someList[3]是someList
列表的第四個(gè)元素(依次類推)。
你可以使用關(guān)鍵字del刪除變量。它也可以用來刪除列表中的元素(就象這里)。
因此del someList[0]刪除someList 列表中的第一個(gè)元素。如果刪除前列表是[1, 2,
3],刪除后就變成了[2, 3]。
在繼續(xù)敘述索引列表中的元素之前,我簡(jiǎn)單解釋一下上面的例子。
這是古老算術(shù)的一個(gè)版本,稱為“The Sieve of Erastothenes”(類似這樣)。它考量一
系列給定數(shù)字(在本例中是一個(gè)列表),然后有組織的刪除已知不是素?cái)?shù)的數(shù)字。如何知
道?只要看看它們是不是可以被分解為其它兩個(gè)數(shù)就可以了。
我們從一個(gè)包含數(shù)字[2...999]的候選列表開始--我們知道1是素?cái)?shù)(事實(shí)上,它可能
是也可能不是,看你問誰了),我們想得到小于1000的所有素?cái)?shù)。(事實(shí)上,我們的候
選列表是[3...999],但是2也是候選數(shù)字,因?yàn)樗俏覀兊牡谝粋€(gè)base)。我們還有個(gè)叫result的列表,它任何時(shí)間都包含著最新的結(jié)果。最初的時(shí)候,它只包含1。我們還有個(gè)叫base的變量。每次循環(huán),我們刪除是它的倍數(shù)的數(shù)字(它總是候選列表中最小的數(shù))。每次循環(huán)之后,我們知道剩下的最小的數(shù)是素?cái)?shù)(因?yàn)樗锌梢苑纸獾臄?shù)我們都刪除了)。
因此,我們把它加入result,并把它設(shè)為新的base,然后從列表里移除它(這樣就不會(huì)對(duì)
它重復(fù)計(jì)算了)。當(dāng)候選列表為空時(shí),result列表將包含所有的素?cái)?shù)。精巧吧,哈!
思考一下:第一次循環(huán)有什么特別嗎?那時(shí)base 是2,但它一樣經(jīng)過了篩選。為什
么?為什么這不發(fā)生在其它的base值身上?我們打算移除product時(shí)能否確定它在候選列
表中呢?為什么?
接下來是什么呢?哦,是的……索引。還有切片。它們是從python列表中獲得單個(gè)
元素的方法。你已經(jīng)見到了普通的索引行為。它相當(dāng)簡(jiǎn)單。事實(shí)上,我已經(jīng)告訴了你所有
你需要知道的關(guān)于它的東西,除了一件事:負(fù)數(shù)索引從列表的末尾向前計(jì)算。所以,
someList[-1]是someList的最后一個(gè)元素,someList[-2]是它之前的一個(gè)元素,依次類
推。
切片,仍然,對(duì)你來說是陌生的。它和索引相似,除了切片可以獲得列表中的所有的
元素,而不僅僅是單個(gè)的元素。這如何做呢?象這樣:
food = [“spam”, “spam”, “eggs”, “sausages”, “spam”]
print food[2:4]
# Prints “['eggs', 'sausages']”
10. 繼續(xù)抽象-對(duì)象和面向?qū)ο缶幊?
現(xiàn)在有個(gè)比較熱門的詞叫做“面向?qū)ο缶幊獭薄?
就象本段標(biāo)題暗示的那樣,面向?qū)ο缶幊虄H僅是另外一種抽象細(xì)節(jié)的方式。程序通過
命名將簡(jiǎn)單的描述抽象為復(fù)雜的操作。在面向?qū)ο缶幊虝r(shí),我們不僅可以這樣對(duì)待程序,
還可以把它們做為對(duì)象。(現(xiàn)在,這肯定會(huì)讓你吃驚,哈?。├纾绻帉憻鹜瘸?
序,我們不用編寫很多過程來處理溫度、時(shí)間、成份等等,我們可以把它們結(jié)合為一個(gè)火
腿對(duì)象?;蛘撸苍S我們可以再有爐子對(duì)象和時(shí)鐘對(duì)象……那么,象溫度這類事物就變成
了火腿對(duì)象的一個(gè)屬性,而時(shí)間可以從時(shí)鐘對(duì)象讀取。要使用我們的程序做某些事,我們
可以教給我們的對(duì)象某些方法;比如,爐子應(yīng)當(dāng)知道如何烹制火腿等。
那么--在python中我們?nèi)绾巫瞿??我們不能直接制造一個(gè)對(duì)象。不能直接制造一個(gè)
爐子,而是做一個(gè)菜譜來描述爐子應(yīng)該是什么樣。這份菜譜因此就描述了一個(gè)被我們稱為
爐子的一類對(duì)象。一個(gè)非常簡(jiǎn)單的爐子類可能是這樣:
class Oven:
def insertSpam(self, spam):
self.spam = spam
def getSpam(self):
return self.spam
這看起來很難理解,還是怎樣呢?
這個(gè)例子中的新東西……
對(duì)象的類用關(guān)鍵字class定義。
類的名稱通常以大寫字母開始,而函數(shù)和變量(還有屬性和方法)的名稱以小寫字
母開始。
方法(也就是讓對(duì)象知道如何去做的函數(shù)和操作)的定義沒有特別,但是要在類的
定義里面。
所有對(duì)象的方法應(yīng)當(dāng)有的第一個(gè)參數(shù)叫做self(或者類似的……)原因很快就清楚
了。
對(duì)象的屬性和方法可以這樣來訪問:mySpam.temperature = 2 或者dilbert.be_nice
()。
我能猜到上面例子中的某些東西你仍然不清楚。例如,什么是self?還有,現(xiàn)在我們
有了對(duì)象菜譜(也就是類),我們?cè)鯓邮聦?shí)上構(gòu)造一個(gè)對(duì)象呢?
我們先顛倒一下順序。對(duì)象通過象引用函數(shù)那樣引用類名來創(chuàng)建:
myOven = Oven()
myOven包含了一個(gè)Oven對(duì)象,通常叫做Oven類的一個(gè)實(shí)例。假設(shè)我們也構(gòu)造好了
一個(gè)Spam類,那么我們可象這樣做:
mySpam = Spam()
myOven.insertSpam(mySpam)
myOven.spam現(xiàn)在將包含mySpam。怎么回事?因?yàn)?,我們調(diào)用一個(gè)對(duì)象的某個(gè)方法
時(shí),第一個(gè)參數(shù),通常稱為self,總是包含對(duì)象本身。(巧妙,哈?。┻@樣,self.spam =spam這一行設(shè)置當(dāng)前Oven對(duì)象的spam屬性的值為參數(shù)spam。注意它們是兩個(gè)不同的事物,盡管在這個(gè)例子中它們都被稱為spam。
11. 練習(xí)3答案
這是這個(gè)運(yùn)算法則的一個(gè)非常簡(jiǎn)潔的版本:
def euclid(a, b):
while b:
a, b = b, a%b
return a
12. 參考
[1]假日火腿沙拉菜譜摘自獺ormel Foods壞繾影娌似住?
Copyright ?nbsp;Magnus Lie Hetland 肯定來過[譯]
相關(guān)文章
python之生成多層json結(jié)構(gòu)的實(shí)現(xiàn)
今天小編就為大家分享一篇python之生成多層json結(jié)構(gòu)的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-02-02淺談python圖片處理Image和skimage的區(qū)別
這篇文章主要介紹了淺談python圖片處理Image和skimage的區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08詳解如何使用Python實(shí)現(xiàn)復(fù)制粘貼的功能
pandas?里面有一個(gè)?pd.read_clipboard?函數(shù),可以根據(jù)你復(fù)制的內(nèi)容生成DataFrame。本文就利用這個(gè)函數(shù)實(shí)現(xiàn)復(fù)制粘貼的功能,感興趣的可以了解一下2023-01-01

對(duì)Django中static(靜態(tài))文件詳解以及{% static %}標(biāo)簽的使用方法
今天小編就為大家分享一篇對(duì)Django中static(靜態(tài))文件詳解以及{% static %}標(biāo)簽的使用方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
2019-07-07