- 你也能看得懂的Python算法書
- 王碩 董文馨 張舒行 張潔編著
- 6725字
- 2019-07-25 11:36:19
1.1 變量
變量在計算機語言中,可以用于存儲不同的計算結果和不同類型的數據,或表示一個數值。變量是可變的,也就是說,它可以被重復賦值。
在認識變量之前,我們先來了解輸入和輸出,這樣才能對程序輸入數據或者看到運行后的結果。
1.1.1 輸出和輸入
我們以非常經典的一項任務入手,在屏幕上輸出一行文字:Hello World!
在Python 3中,實現這個任務只需要一行代碼(Python中“#”后方的文字為注釋,不影響程序運行,詳細信息見1.1.5節最后)。
01 print("Hello World!") #注意:編寫程序時一定要用英文輸入法!
運行程序,輸出結果為:
Hello World!
在這一行程序中,print()是用于輸出的函數,“Hello World!”是輸出的數據。其中雙引號代表數據是一個字符串。
我們再來看如何輸入數據。如果想輸入一個數字,把它除以2然后打印出來,該怎么做呢?下面的程序就實現了這個功能。
01 num=int(input("Enter a number:")) #輸入一個數字,用變量num存儲
02 num=num/2 #把num除以2
03 print(num) #輸出num的值
運行程序,程序輸出如下:
Enter a number:
此時可以輸入任意整數。我們輸入6,程序輸出3后結束。
在程序的第一行中,新建了變量num來存儲輸入的數據。因為這個變量是用于存儲一個數的,所以把它命名為num,這樣比較直觀易懂。只要遵守變量的命名法則(參見本小節末尾),那么可以隨意為變量取名。
在第一行中,input()函數用于輸入數據,括號內的字符串是提示語,就是在輸入數據之前輸出的那一段字符串。如果括號內沒有內容(input()),則不輸出任何文字,用戶直接輸入數據即可。而input()函數外面套著的int()函數則是用于把數據轉換為int類型的函數。Input()函數返回的值默認為字符串類型(string),字符串不可以進行數學運算。所以,我們使用 int()函數先把字符串轉換為整型(int),再進行賦值、運算并輸出。數據類型的知識會在下一小節介紹。
程序中的“=”用于給變量賦值,不是相等的意思。“=”左邊必須是一個可以被賦值的變量,“=”右邊可以是一個常量、變量或函數的返回值等。賦值語句運行結束后,“=”左邊的變量的值更新為“=”右邊的值。與其他編程語言不同,由于 Python 中變量的類型不固定,所以被賦值的變量的數據類型同樣可以被更新,如下面的程序所示。

運行這段程序,輸出結果為abcd。
在這一小節中我們了解了輸入和輸出,也對變量的概念有了初步認識。為了避免程序出錯,以下是變量命名的幾項法則:
變量名中只能出現字母、數字和下畫線,且第一個字符不能是數字。比如,可以將變量命名為name_6,但不能將變量命名為6_name。
不要把在Python中有特殊用途的單詞作為變量名,如函數名。比如,目前我們接觸過的print函數,如果把print作為一個變量名稱,運行程序時又用到print函數,編譯器就會報錯。
下面就是一個例子:
01 print=0
02 print(print) #print函數無法被調用,print被系統認為是變量名稱了
一個變量名對應一個變量,不會有兩個變量有相同的變量名。變量的名字最好和變量的功能相對應,比如一個存儲平均數的變量,將它命名為average比命名為abcd要直觀,這樣不容易記錯變量名稱而導致程序出錯。
1.1.2 簡單變量類型
Python語言中有5種標準變量類型:數字、字符串、列表、元組和字典,其中數字和字符串是比較簡單的,本小節主要介紹這兩種變量類型。
首先,我們來仔細了解一下變量的概念。每個變量都有一個獨特的變量名,我們通過這個獨特的變量名來調用這個變量的值。就像圖1.1中的氣球和牌子一樣,人夠不著氣球,但是可以通過扯動牌子來拿到氣球。每個牌子都對應一個單獨的氣球。牌子就相當于變量名,而氣球就相當于變量存儲的值。
現在我們知道了變量的概念,再來分類型介紹變量。
數字類型的變量是最常用的一種。數字類型還可以再細分,其中主要的兩種類型為整型(int)和浮點型(float)。整型變量只能存儲整數,浮點型變量則可以存儲小數。

圖1.1 變量與變量名
例如:
01 num1=10
02 num2=10.0
在這兩行程序中,num1表示的值是整數10,num2表示的值是小數10.0。盡管這兩個變量所表示的數的大小是相等的,但它們并不是同一種類型的變量。不過,它們的類型是可以相互轉換的。
01 num1=10
02 num2=10.99
03 num1=float(num1)
04 num2=int(num2)
05 print(num1,num2)
運行程序,輸出結果為:
10.0 10
其中,10.0是輸出時num1的值,10是輸出時num2的值。在程序中,float函數的作用是把整型變量轉換為浮點型變量,而int函數的作用是把浮點型變量轉換為整型變量。如果你足夠細心,會發現原本值為10.99的num2在轉換為整型之后變為了10,它的值改變了。這是因為,在Python中,不存在四舍五入,取整指的是丟棄原值小數點后的部分。
這段程序中還涉及了關于print函數的新語法。我們使用print(num1,num2),在同一行輸出兩個值,中間用空格隔開。
這就好比用一個盒子搬運東西,本來盒子中有多個格子,每個格子都可以裝一件物品。使用print(num1)加上print(num2)就是每次只用其中的一個格子來搬運東西,所以需要分成兩次搬運;print(num1,num2)就是同時用兩個格子裝物品,一次搬運就可以完成。print函數就是一個有無數格子的箱子,只要需要就可以使用,如圖1.2所示。

圖1.2 print函數與盒子
講完了新語法,我們再來看看用舊語法輸出兩個變量時的情況。如果采用分兩次print的方法來輸出,結果會是兩個數分別在兩行:
......
05 print(num1)
06 print(num2)
運行程序,輸出結果為:
10.0
10
第二種常用的數據類型是字符串,字符串就是一串字符。在Python中,兩個單引號或者兩個雙引號之間的一串字符就是字符串。需要注意的是,如果你使用單引號來表示字符串,那么字符串中不能包含撇號。
01 text1="I'm a programmer."
02 text2='I'm a programmer.'
以上兩種字符串定義方式中,第二種是不可行的。系統會認為前單引號和撇號中間的文本I為需要定義的字符串,后面字符則會被判定為非法字符,從而導致程序出錯。
如果換一個思路,按照下面的方法來定義,就是可行的了。
01 text1="I'm a programmer."
02 text2='I am a programmer.'
1.1.3 數學計算
在Python中,可以對數字進行加減乘除運算。其中,加對應“+”,減對應“-”,乘對應“*”,除對應“/”。
以下是Python 3中整數運算的程序:
01 print(5+2)
02 print(5-2)
03 print(5*2)
04 print(5/2)
運行程序,輸出結果為:
7
3
10
2.5
值得注意的是,在Python 3中,如果整數相除的結果不是整數,Python會把運算的結果存儲為浮點型的變量。
我們來看一看浮點數的運算:
01 print(0.3+0.2)
02 print(0.3-0.2)
03 print(0.3*0.2)
04 print(0.3/0.2)
運行程序,輸出結果為:
0.5
0.09999999999999998
0.06
1.49999999999999998
在浮點數的運算中有時會出現第二個和第四個運算結果這樣的情況。計算機內部表示數字的方式使得有時表示運算結果出現困難,最后輸出一個十分近似真實結果的值。所有語言都存在這樣的問題,不必擔心。
除了簡單的加減乘除運算,Python中還有許多內置函數,可以對數字進行更復雜的運算。調用這些函數比自己寫出實現這些功能的代碼要快得多,從而可以大大提高程序的效率,也可以提高程序的運行速度。下面我們來了解幾個常用的數學函數。
pow函數是十分常見的一個函數,通常用于求一個數的n次方。
01 print(pow(4,2))
02 print(pow(4,2,3))
運行這段程序,輸出結果為:
16
1
在這段程序中,我們見到了pow函數的兩種使用方法。pow函數的使用格式為pow(x,y,z),如果括號內沒有填寫z,也就是只輸入了兩個數的話,pow函數的返回值為x的y次方。如果輸入了z,那么pow的返回值就是x的y次方除以z的余數,即x**y%z。在Python中,符號“%”是取余的意思,“a%b”就是a除以b的余數。
在這段程序中,第一行輸出的是4的2次方,也就是16;第二行輸出的是4的2次方除以3的余數,也就是16/3的余數1。
接下來要了解的函數是abs函數和sqrt函數。
01 import math
02 num=-4
03 num=abs(num)
04 print(math.sqrt(num))
運行程序,輸出結果為:
2.0
這段程序中使用了用于求絕對值的abs函數和用于求平方根的sqrt函數。我們知道,負數是沒有實數根的,所以在開方之前先用abs函數把num變成非負數,再把abs函數返回的值賦給num,從而達到更新num的值的效果。第3行運行結束時num的值為4。
第4行使用sqrt函數來求num的平方根。由于sqrt函數不處于默認模塊中,所以要先導入包含sqrt的math模塊,使用import語句來導入。調用sqrt函數時,函數名前面要加上“math.”,表示它是math模塊內的函數,這樣計算機才能找到它。sqrt函數的返回值是浮點型。
Python中還有許多內置函數,在以后的學習和使用中你會逐漸接觸到。
1.1.4 位運算
位運算的符號是把變量當作二進制數來進行運算的。
在了解位運算之前,我們先來看一看二進制和我們平時使用的十進制有什么相似和不同之處,為熟練使用位運算打好基礎。如果已經對二進制很熟悉,可以跳過這一段,直接進入講解位運算的部分。
我們先以一個十進制數為例。
十進制數62,它的值由6*10+2*1組成。我們知道,在十進制數中,個位代表10的0次方,十位代表10的1次方,百位代表10的2次方,千位代表10的3次方,依此類推。從右到左,第n個數位上的數字代表著有多少個10的n-1次方相加。對于二進制數來說,這個規律也同樣適用,只不過數字從滿10進一位變成了滿2進一位。從右到左,一個二進制數的第一位代表2的0次方,第二位代表2的1次方,第三位代表2的2次方,第四位代表2的3次方……但是,由于一個數位上的數只要滿2就必須進位,所以二進制數只由1和0組成。
以十進制數62為例(如圖1.3所示),把它化成一個二進制的數。

圖1.3 用十進制表示62
先把運算過程用圖1.4表示出來:

圖1.4 用二進制表示62
為了方便理解,把得到的二進制的數每4個數位為一組,中間以空格隔開。
62=2*2*2*2*2+2*2*2*2+2*2*2+2*2+2
62=0011 1110
我們看到,62被拆分成多個2的不同次冪的和。每一個冪對應著二進制數的數位上的一個1,而那些沒有出現的冪(比如2的0次方),它們的數位上則是0。
所以,二進制數中的1和0也可以被看作“是”和“否”,就像一個開關一樣。像圖1.5中一樣,一個格子就是一盞燈,白色的格子代表燈亮起,亮起的燈就是“是”,代表這個數位上是一個1,也代表計算這個數的值時要加上這個數位。

圖1.5 用燈的亮滅表示二進制數
現在,把十進制數轉換為二進制數之后,再試著把它轉換回原來的十進制數,驗證一下是否正確。
明白了二進制數的概念之后,再來了解位運算的各個符號。
第一個符號是按位與運算符&。參與運算的兩個值中,只有對應數位上都是1時,那個數位的運算結果才是1,否則運算結果的對應數位是0。
用62和21來做一次與運算,從而更直觀地理解按位與運算符。
01 a=62 #a=0011 1110
02 b=21 #b=0001 0101
03 c=a&b #c=0001 0100
04 print(c)
運行程序,輸出結果為:
20
在Python的語法中,我們不能直接定義二進制數,只能定義十進制數,但是進行位運算時,計算機會把十進制數轉換為二進制數進行計算,再把二進制的結果轉換為十進制數輸出。
下面來分析一下這次位運算的過程。
首先,把a和b這兩個數換算成二進制數,再把每一個數位對齊。
a : 0011 1110
b : 0001 0101
c : 0001 0100
進行按位與運算后,只有(從右到左的)第三位和第五位上,a和b的值都是1,其他位上要么只有一個1,要么就都是0。所以,結果c中只有第三位和第五位上是1,其他位都是0。把運算結果c換算成十進制數,就是20。
在介紹完位運算具體實現的過程之后,就可以繼續了解其他的位運算符號了。
第二個位運算符號是按位或運算符|。它的運算方法和按位與類似,也是對換成二進制的兩個數的對應數位進行運算。不同的是,兩個數的數位中只要有一個是1,結果就是1。
我們來用運算過程來說明按位或運算符的使用方法:
01 a=62 #a=0011 1110
02 b=21 #b=0001 0101
03 c=a|b #c=0011 1111
04 print(c)
運行程序,輸出結果為:
63
同樣把三個數的數位對齊,來看看按位或運算符的操作過程:
a : 0011 1110
b : 0001 0101
c : 0001 1111
只有前兩個數位上,兩個數都沒有1存在,所以最終答案里只有前兩位為0。最后,把答案c換算成十進制數,是63。
第三個運算符是按位異或運算符^。這次的運算規則是這樣的:對應數位上的數不同時,結果中的數位為1;對應數位上的數相同時,結果中的數位為0。
直接來看一個應用按位異或運算符的例子:
01 a=62 #a=0011 1110
02 b=21 #b=0001 0101
03 c=a^b #ans=0010 1011
04 print(c)
同樣的,還是把三個數的每個數位對齊來觀察按位異或運算的規律:
a : 0011 1110
b : 0001 0101
c : 0010 1011
從右到左,第一個、第二個、第四個、第六個數位上,要么是a的數位的值是1、b的數位的值是0,要么是a的數位的值是0,b的數位的值是1。就這樣,最終答案就出現了。
最后兩個運算符是左移和右移位運算符。左移運算符是<<,右移運算符是>>。這兩個運算符的作用,是把一個變量的值化成二進制之后,再把它的整體數位向左移或向右移指定的位數。比如,“a<<2”就是把a的二進制數的數位整體往左移動兩位之后再轉換回十進制數。如果是往左移,那么被覆蓋的高位就消失了,而空出來的低位用0補上。如果是往右移則剛好相反,被覆蓋的低位消失了,空出來的高位則變成了0。
還是用圖來展示這個過程吧,參見圖1.6。

圖1.6 二進制數向左移動兩位
在圖1.6中,上面是原來的二進制數,下面是向左移動兩位后的二進制數。可以看到,向左移動兩位后,原來是2的5次方到2的1次方這些數位上是1,現在變成了2的7次方到2的3次方這些數位上是1。原本2的7次方和6次方數位上的數被覆蓋而消失了。
同時,我們發現,原本在2的0次方數位上的數移動到了2的2次方的數位上。此時,2的1次方和2的0次方就空了出來。用0填補上這些空位。這樣,就完成了一次移動。
看完了圖1.6之后,再來看一看在程序中該如何實現二進制數的左移和右移。通過下面的例子,你會更直觀地了解這兩個運算符的作用。
01 a=62 #a=0011 1110
02 b=21 #b=0001 0101
03 print(a<<2) #a<<2=1111 1000
04 print(b>>1) #b>>1=0000 1010
運行程序,輸出結果為:
248
12
從程序的注釋中可以看到a、b以及運算結果轉換為二進制數的效果。左移和右移位運算符是可以自行定義不同的移動位數的,所以你也可以嘗試設兩個數來驗證自己對這兩個運算符的理解。
1.1.5 使用字符串
可以使用字符串在編程時進行文本處理和判斷。本節主要講解字符串的一些使用和處理方法,涉及一些常用的字符串內建函數。
首先是字符串的拼接。在 Python 中,字符串可以使用“+”進行拼接,就像做數學題的加法一樣。很多時候都需要拼接字符串。比如,如果想把日期和星期幾拼接起來,就要用到這個方法。下面展示了解決這個問題的一段程序:
01 date="2018.2.16"
02 day="Friday"
03 text=date+" "+day
04 print(text)
運行程序,輸出結果為:
2018.2.16 Friday
在程序的第3行中,新建了一個字符串變量text,用于把字符串date和字符串day拼在一起。為了美觀,在中間加上一個空格。由此可以直觀地得出,字符串的拼接是按從左往右的順序進行的。
01 date="2018.2.16"
02 day="Friday"
03 print(date+" "+day)
這段程序的輸出結果和上一段程序是相同的。
需要注意的是,如果你想在字符串中添加數字,這些數字也必須是字符串類型的變量。
我們來看一個典型的錯誤例子:
01 age=94
02 text="Age:"
03 combine=text+age
04 print(combine)
其中,age 是一個整型變量,并不是字符串變量,所以運行到第3行拼接字符串的時候程序會出錯。正確的做法是把age轉換為字符串類型后再拼接:
01 age=94
02 text="Age:"
03 combine=text+str(age)
04 print(combine)
當然,如果換一種思路,不把age轉換為字符串也是可以的:
01 age=94
02 text="Age:"
03 print(text,age)
這種方法有一點小缺陷:print函數的括號內用逗號隔開的變量,在輸出時中間會有空格。
在字符串的處理中,大小寫的轉換也是十分實用的一項技術,這是我們需要了解的第二個方面。
首先來了解lower和upper這兩個字符串內建函數:
01 name="Adam Smith"
02 print(name.lower())
03 print(name.upper())
運行這段程序,輸出結果為:
adam smith
ADAM SMITH
觀察這段程序可以發現,lower函數的作用是把字符串中的英文字符全部轉換為小寫形式,而upper函數的作用剛好相反,把所有英文字母都轉換為大寫形式。
我們仔細地來研究一下這兩個函數,函數有時也稱作方法。upper與lower相似,我們只以lower為例,它的格式為:name.lower(),其中,name是字符串的變量名,方法lower()與name中間用一個句點連接。方法是 Python 可以對數據進行的操作。句點使 Python 對句點前的變量執行句點后的方法。一般來講,方法的執行需要額外的信息,在方法名后面的括號內提供。lower和upper方法不需要額外的信息,所以括號內為空,但是必須保留括號。字符串名+句點+(數據),這是大多數內建函數的格式。
接下來講解capitalize和title這兩個內建函數。來看下面的程序:
01 name="adam smith"
02 print(name.capitalize())
03 print(name.title())
運行程序,輸出結果為:
Adam smith
Adam Smith
根據程序的運行結果可以推斷出,capitalize的功能是把字符串的第一個字母字符變為大寫(如果第一個字符不是字母則不變),title的功能是把字符串內每一個單詞的首字母都變為大寫,(單詞之間由不是字母的字符隔開時,如“good9day”,用title方法操作后變為“Good9Day”)。這兩個內建函數的點結構和上面所講的lower和upper相似。
第三點要講的是轉義字符。為了輸出時的美觀,常常需要把一串字符分隔開來在不同行輸出,或者在不同的字符前添加縮進。如何才能在同一個字符串內實現這些功能而不用多次print呢?
請看下面的程序:
01 text="Python\nC\nJava"
02 print(text)
運行程序,輸出結果為:
Python
C
Java
在字符串text中,\n叫作換行符,是Python中轉義字符的一種。這代表Python在輸出這些字符時,不會輸出它們原本的組成字符,而是會輸出它們對應的功能,比如\n對應換行。同樣,要想在文本中添加縮進也可以使用類似的方法:
01 text="Programming Language:\n\tPython\n\tC\n\tJava"
02 print(text)
運行程序,輸出結果為:
Programming Language:
Python
C
Java
其中,往字符串中添加\t就是添加橫向制表符,從而達到縮進的效果。
除了上面主要講述的兩種轉義字符,Python中還有許多轉義字符,如表1.1所示。
表1.1 轉義字符表

第四個技巧是如何重復輸出字符串。比如,想要重復輸出“Python”這個單詞三次,每次輸出后都換一行。這時可以使用如下方法:
01 text="Python\n"
02 print(text*3)
運行程序,輸出結果為:
Python
Python
Python
重復輸出字符串的方法就像在做數學中的乘法一樣。在合適的時候使用它可以大大提高編寫程序的效率。
第五點是編寫注釋。注釋是指存在于程序中但對程序運行效果不產生影響的文字,在程序運行過程中它會被計算機忽略。在編寫程序時,如果程序較長或者它的邏輯結構十分復雜,添加注釋可以有效地幫助我們看懂程序的結構和作用。妙用注釋對于程序員來說有巨大的幫助。
在一行字符前面加上#就可以讓這一行出現在#后面的字符全部變成注釋。如果需要多行注釋,則在每行文字前都加上#即可。
01 n=1+2+3
02 print(n) #print the value of n
需要注意的是,Python中的注釋最好用英文和數字來寫。如果在注釋中使用中文,則程序在運行過程中有可能出錯(即使注釋并不是程序要運行的一部分),這取決于編譯器的類型和使用的語言。本書中為使大家更好地明白書中要講解的內容,大部分使用中文編寫注釋。
- Computer Vision for the Web
- Architecting the Industrial Internet
- 你不知道的JavaScript(中卷)
- 移動界面(Web/App)Photoshop UI設計十全大補
- 利用Python進行數據分析
- Test-Driven Machine Learning
- Zabbix Performance Tuning
- INSTANT JQuery Flot Visual Data Analysis
- 深度學習入門:基于Python的理論與實現
- After Effects CC案例設計與經典插件(視頻教學版)
- 深入理解Java虛擬機:JVM高級特性與最佳實踐
- Spring Web Services 2 Cookbook
- Practical Time Series Analysis
- Azure for Architects
- 陪孩子像搭積木一樣學編程:Python真好玩+Scratch趣味編程(全2冊)