本篇文章全部copy自廖雪峰老師的Python入門教程,僅供學(xué)習(xí)用
教程鏈接:Python入門
數(shù)據(jù)類型
整數(shù)
py可以處理任意大小的整數(shù),包括負(fù)整數(shù)
浮點數(shù)
1.23x109和12.3x108是相等的。浮點數(shù)可以用數(shù)學(xué)寫法,如1.23,3.14,-9.01,等等。但是對于很大或很小的浮點數(shù),就必須用科學(xué)計數(shù)法表示,把10用e替代,1.23x10^9就是1.23e9,或者12.3e8,0.000012可以寫成1.2e-5,等等。
整數(shù)和浮點數(shù)在計算機內(nèi)部存儲的方式是不同的,整數(shù)運算永遠(yuǎn)是精確的(除法難道也是精確的?是的!),而浮點數(shù)運算則可能會有四舍五入的誤差。
字符串
是以''和""括起來的任意文本
布爾值
一個布爾值只有True和False,布爾值可以用and、or和not運算。
and運算是與運算,只有所有都為 True,and運算結(jié)果才是 True。
or運算是或運算,只要其中有一個為 True,or 運算結(jié)果就是 True。
not運算是非運算,它是一個單目運算符,把 True 變成 False,F(xiàn)alse 變成 True。
空值
None表示
其它
py還提供了列表,字典等多種數(shù)據(jù)類型,還允許自定義數(shù)據(jù)類型。
Python2 里面print可以直接接字符串或者運算。
Python3 里面print變成了一個函數(shù),上面的寫法不支持了,必須用一個括號括起來,否則會報告語法錯誤。
print語句
1.當(dāng)我們在Python交互式環(huán)境下編寫代碼時,>>>是Python解釋器的提示符,不是代碼的一部分。
2.當(dāng)我們在文本編輯器中編寫代碼時,千萬不要自己添加 >>>。
print語句也可以跟上多個字符串,用逗號“,”隔開,就可以連成一串輸出:
>>> print 'The quick brown fox', 'jumps over', 'the lazy dog'
The quick brown fox jumps over the lazy dog
print會依次打印每個字符串,遇到逗號“,”會輸出一個空格,因此,輸出的字符串是這樣拼起來的:

print也可以打印整數(shù),或者計算結(jié)果:
>>> print 300
300 #運行結(jié)果
>>> print 100 + 200
300 #運行結(jié)果
注釋
以#開頭,后面的文字直到行尾都算注釋
變量
在Python程序中,變量是用一個變量名表示,變量名必須是大小寫英文、數(shù)字和下劃線(_)的組合,且不能用數(shù)字開頭,比如:
a = 1
變量a是一個整數(shù)。
t_007 = 'T007'
變量t_007是一個字符串。
在Python中,等號=是賦值語句,可以把任意數(shù)據(jù)類型賦值給變量,同一個變量可以反復(fù)賦值,而且可以是不同類型的變量,例如:
a = 123 # a是整數(shù)
print a
a = 'imooc' # a變?yōu)樽址?br>
print a
這種變量本身類型不固定的語言稱之為動態(tài)語言,與之對應(yīng)的是靜態(tài)語言。靜態(tài)語言在定義變量時必須指定變量類型,如果賦值的時候類型不匹配,就會報錯。例如Java是靜態(tài)語言
最后,理解變量在計算機內(nèi)存中的表示也非常重要。當(dāng)我們寫:a = 'ABC'時,Python解釋器干了兩件事情:
在內(nèi)存中創(chuàng)建了一個'ABC'的字符串;
在內(nèi)存中創(chuàng)建了一個名為a的變量,并把它指向'ABC'。
也可以把一個變量a賦值給另一個變量b,這個操作實際上是把變量b指向變量a所指向的數(shù)據(jù),例如下面的代碼:
a = 'ABC'
b = a
a = 'XYZ'
print b

字符串
前面我們講解了什么是字符串。字符串可以用''或者""括起來表示。
如果字符串本身包含'怎么辦?比如我們要表示字符串 I'm OK ,這時,可以用" "括起來表示:
"I'm OK"
類似的,如果字符串包含",我們就可以用' '括起來表示:
'Learn "Python" in imooc'
如果字符串既包含'又包含"怎么辦?
這個時候,就需要對字符串的某些特殊字符進(jìn)行“轉(zhuǎn)義”,Python字符串用\進(jìn)行轉(zhuǎn)義。
要表示字符串 Bob said "I'm OK".
由于 ' 和 " 會引起歧義,因此,我們在它前面插入一個\表示這是一個普通字符,不代表字符串的起始,因此,這個字符串又可以表示為
'Bob said "I'm OK".'
注意:轉(zhuǎn)義字符 \ 不計入字符串的內(nèi)容中。
常用的轉(zhuǎn)義字符還有:
\n 表示換行
\t 表示一個制表符
\ 表示 \ 字符本身
raw字符串與多行字符串
如果一個字符串包含很多需要轉(zhuǎn)義的字符,對每一個字符都進(jìn)行轉(zhuǎn)義會很麻煩。為了避免這種情況,我們可以在字符串前面加個前綴 r ,表示這是一個 raw 字符串,里面的字符就不需要轉(zhuǎn)義了。例如:
r'(_)/ (_)/'
但是r'...'表示法不能表示多行字符串,也不能表示包含'和 "的字符串(為什么?)
如果要表示多行字符串,可以用'''...'''表示:
'''Line 1
Line 2
Line 3'''
上面這個字符串的表示方法和下面的是完全一樣的:
'Line 1\nLine 2\nLine 3'
還可以在多行字符串前面添加 r ,把這個多行字符串也變成一個raw字符串:
r'''Python is created by "Guido".
It is free and easy to learn.
Let's start learn Python in imooc!'''
Unicode字符串
因為計算機只能處理數(shù)字,如果要處理文本,就必須先把文本轉(zhuǎn)換為數(shù)字才能處理。最早的計算機在設(shè)計時采用8個比特(bit)作為一個字節(jié)(byte),所以,一個字節(jié)能表示的最大的整數(shù)就是255(二進(jìn)制11111111=十進(jìn)制255),0 - 255被用來表示大小寫英文字母、數(shù)字和一些符號,這個編碼表被稱為ASCII編碼,比如大寫字母 A 的編碼是65,小寫字母 z 的編碼是122。
如果要表示中文,顯然一個字節(jié)是不夠的,至少需要兩個字節(jié),而且還不能和ASCII編碼沖突,所以,中國制定了GB2312編碼,用來把中文編進(jìn)去。
類似的,日文和韓文等其他語言也有這個問題。為了統(tǒng)一所有文字的編碼,Unicode應(yīng)運而生。Unicode把所有語言都統(tǒng)一到一套編碼里,這樣就不會再有亂碼問題了。
Unicode通常用兩個字節(jié)表示一個字符,原有的英文編碼從單字節(jié)變成雙字節(jié),只需要把高字節(jié)全部填為0就可以。
因為Python的誕生比Unicode標(biāo)準(zhǔn)發(fā)布的時間還要早,所以最早的Python只支持ASCII編碼,普通的字符串'ABC'在Python內(nèi)部都是ASCII編碼的。
Python在后來添加了對Unicode的支持,以Unicode表示的字符串用u'...'表示,比如:
print u'中文'
中文
注意: 不加 u ,中文就不能正常顯示。
Unicode字符串除了多了一個 u 之外,與普通字符串沒啥區(qū)別,轉(zhuǎn)義字符和多行表示法仍然有效:
轉(zhuǎn)義:
u'中文\n日文\n韓文'
多行:
u'''第一行
第二行'''
raw+多行:
ur'''Python的Unicode字符串支持"中文",
"日文",
"韓文"等多種語言'''
如果中文字符串在Python環(huán)境下遇到 UnicodeDecodeError,這是因為.py文件保存的格式有問題??梢栽诘谝恍刑砑幼⑨?/p>
# -*- coding: utf-8 -*-
目的是告訴Python解釋器,用UTF-8編碼讀取源代碼。然后用Notepad++ 另存為... 并選擇UTF-8格式保存。
整數(shù)和浮點數(shù)
Python支持對整數(shù)和浮點數(shù)直接進(jìn)行四則混合運算,運算規(guī)則和數(shù)學(xué)上的四則運算規(guī)則完全一致。
基本的運算:
1 + 2 + 3 # ==> 6
4 * 5 - 6 # ==> 14
7.5 / 8 + 2.1 # ==> 3.0375
使用括號可以提升優(yōu)先級,這和數(shù)學(xué)運算完全一致,注意只能使用小括號,但是括號可以嵌套很多層:
(1 + 2) * 3 # ==> 9
(2.2 + 3.3) / (1.5 * (9 - 0.3)) # ==> 0.42145593869731807
和數(shù)學(xué)運算不同的地方是,Python的整數(shù)運算結(jié)果仍然是整數(shù),浮點數(shù)運算結(jié)果仍然是浮點數(shù):
1 + 2 # ==> 整數(shù) 3
1.0 + 2.0 # ==> 浮點數(shù) 3.0
但是整數(shù)和浮點數(shù)混合運算的結(jié)果就變成浮點數(shù)了:
1 + 2.0 # ==> 浮點數(shù) 3.0
為什么要區(qū)分整數(shù)運算和浮點數(shù)運算呢?這是因為整數(shù)運算的結(jié)果永遠(yuǎn)是精確的,而浮點數(shù)運算的結(jié)果不一定精確,因為計算機內(nèi)存再大,也無法精確表示出無限循環(huán)小數(shù),比如 0.1 換成二進(jìn)制表示就是無限循環(huán)小數(shù)。
那整數(shù)的除法運算遇到除不盡的時候,結(jié)果難道不是浮點數(shù)嗎?我們來試一下:
11 / 4 # ==> 2
令很多初學(xué)者驚訝的是,Python的整數(shù)除法,即使除不盡,結(jié)果仍然是整數(shù),余數(shù)直接被扔掉。不過,Python提供了一個求余的運算 % 可以計算余數(shù):
11 % 4 # ==> 3
如果我們要計算 11 / 4 的精確結(jié)果,按照“整數(shù)和浮點數(shù)混合運算的結(jié)果是浮點數(shù)”的法則,把兩個數(shù)中的一個變成浮點數(shù)再運算就沒問題了:
11.0 / 4 # ==> 2.75
布爾類型
布爾類型只有True和False兩種值,但是布爾類型有以下幾種運算:
與運算:只有兩個布爾值都為 True 時,計算結(jié)果才為 True。
True and True # ==> True
True and False # ==> False
False and True # ==> False
False and False # ==> False
或運算:只要有一個布爾值為 True,計算結(jié)果就是 True。
True or True # ==> True
True or False # ==> True
False or True # ==> True
False or False # ==> False
非運算:把True變?yōu)镕alse,或者把False變?yōu)門rue:
not True # ==> False
not False # ==> True
布爾運算在計算機中用來做條件判斷,根據(jù)計算結(jié)果為True或者False,計算機可以自動執(zhí)行不同的后續(xù)代碼。
在Python中,布爾類型還可以與其他數(shù)據(jù)類型做 and、or和not運算,請看下面的代碼:
a = True
print a and 'a=T' or 'a=F'
計算結(jié)果不是布爾類型,而是字符串 'a=T',這是為什么呢?
因為Python把0、空字符串''和None看成 False,其他數(shù)值和非空字符串都看成 True,所以:
True and 'a=T' 計算結(jié)果是 'a=T'
繼續(xù)計算 'a=T' or 'a=F' 計算結(jié)果還是 'a=T'
要解釋上述結(jié)果,又涉及到 and 和 or 運算的一條重要法則:短路計算。
在計算 a and b 時,如果 a 是 False,則根據(jù)與運算法則,整個結(jié)果必定為 False,因此返回 a;如果 a 是 True,則整個計算結(jié)果必定取決與 b,因此返回 b。
在計算 a or b 時,如果 a 是 True,則根據(jù)或運算法則,整個計算結(jié)果必定為 True,因此返回 a;如果 a 是 False,則整個計算結(jié)果必定取決于 b,因此返回 b。
所以Python解釋器在做布爾運算時,只要能提前確定計算結(jié)果,它就不會往后算了,直接返回結(jié)果。
創(chuàng)建List
list是數(shù)學(xué)意義上的有序集合,也就是說,list中的元素是按照順序排列的。
構(gòu)造list非常簡單,按照上面的代碼,直接用 [ ] 把list的所有元素都括起來,就是一個list對象。通常,我們會把list賦值給一個變量,這樣,就可以通過變量來引用list:
由于Python是動態(tài)語言,所以list中包含的元素并不要求都必須是同一種數(shù)據(jù)類型,我們完全可以在list中包含各種數(shù)據(jù):
>>> L = ['Michael', 100, True]
一個元素也沒有的list,就是空list:
>>> empty_list = []
- 列表可以倒序訪問
- append()可添加新元素到list的尾部
- inser(0,"Paul"),'Paul'將被添加到索引為 0 的位置上(也就是第一個),而原來索引為 0 的Adam同學(xué),以及后面的所有同學(xué),都自動向后移動一位。
- pop()方法刪除最后一個,加索引可刪去索引對應(yīng)的元素
- 替換元素
創(chuàng)建tuple
tuple是另一種有序的列表,中文翻譯為“ 元組 ”。tuple 和 list 非常類似,但是,tuple一旦創(chuàng)建完畢,就不能修改了。
同樣是表示班里同學(xué)的名稱,用tuple表示如下:
>>> t = ('Adam', 'Lisa', 'Bart')
創(chuàng)建tuple和創(chuàng)建list唯一不同之處是用( )替代了[ ]。
現(xiàn)在,這個 t 就不能改變了,tuple沒有 append()方法,也沒有insert()和pop()方法。所以,新同學(xué)沒法直接往 tuple 中添加,老同學(xué)想退出 tuple 也不行。
獲取 tuple 元素的方式和 list 是一模一樣的,我們可以正常使用 t[0],t[-1]等索引方式訪問元素,但是不能賦值成別的元素
單元素tuple
tuple和list一樣,可以包含 0 個、1個和任意多個元素。
包含多個元素的 tuple,前面我們已經(jīng)創(chuàng)建過了。
包含 0 個元素的 tuple,也就是空tuple,直接用 ()表示:
>>> t = ()
>>> print t
()
創(chuàng)建包含1個元素的 tuple 呢?來試試:
>>> t = (1)
>>> print t
1
好像哪里不對!t 不是 tuple ,而是整數(shù)1。為什么呢?
因為()既可以表示tuple,又可以作為括號表示運算時的優(yōu)先級,結(jié)果 (1) 被Python解釋器計算出結(jié)果 1,導(dǎo)致我們得到的不是tuple,而是整數(shù) 1。
正是因為用()定義單元素的tuple有歧義,所以 Python 規(guī)定,單元素 tuple 要多加一個逗號“,”,這樣就避免了歧義:
>>> t = (1,)
>>> print t
(1,)
Python在打印單元素tuple時,也自動添加了一個“,”,為了更明確地告訴你這是一個tuple。
多元素 tuple 加不加這個額外的“,”效果是一樣的:
>>> t = (1, 2, 3,)
>>> print t
(1, 2, 3)
if語句
age = 20
if age >= 18:
print 'your age is', age
print 'adult'
print 'END'
注意: Python代碼的縮進(jìn)規(guī)則。具有相同縮進(jìn)的代碼被視為代碼塊,上面的3,4行 print 語句就構(gòu)成一個代碼塊(但不包括第5行的print)。如果 if 語句判斷為 True,就會執(zhí)行這個代碼塊。
縮進(jìn)請嚴(yán)格按照Python的習(xí)慣寫法:4個空格,不要使用Tab,更不要混合Tab和空格,否則很容易造成因為縮進(jìn)引起的語法錯誤。
注意: if 語句后接表達(dá)式,然后用:表示代碼塊開始。
如果你在Python交互環(huán)境下敲代碼,還要特別留意縮進(jìn),并且退出縮進(jìn)需要多敲一行回車:
>>> age = 20
>>> if age >= 18:
... print 'your age is', age
... print 'adult'
...
your age is 20
adult
if else
if age >= 18:
print 'adult'
else:
print 'teenager'
利用 if ... else ... 語句,我們可以根據(jù)條件表達(dá)式的值為 True 或者 False ,分別執(zhí)行 if 代碼塊或者 else 代碼塊。
if ...else if...
if age >= 18:
print 'adult'
elif age >= 6:
print 'teenager'
elif age >= 3:
print 'kid'
else:
print 'baby'
for 循環(huán)
L = ['Adam', 'Lisa', 'Bart']
for name in L:
print name
while 循環(huán)
N = 10
x = 0
while x < N:
print x
x = x + 1
break 退出循環(huán)
sum = 0
x = 1
while True:
sum = sum + x
x = x + 1
if x > 100:
break
print sum
繼續(xù)循環(huán)
for x in L:
if x < 60:
continue
sum = sum + x
n = n + 1
多重循環(huán)
for x in ['A', 'B', 'C']:
for y in ['1', '2', '3']:
print x + y
dict
這個應(yīng)該是字典的意思,就是鍵值對集合
d = {
'Adam': 95,
'Lisa': 85,
'Bart': 59
}
可以簡單地使用 d[key] 的形式來查找對應(yīng)的 value,這和 list 很像,不同之處是,list 必須使用索引返回對應(yīng)的元素,而dict使用key:
>>> print d['Adam']
95
>>> print d['Paul']
Traceback (most recent call last):
File "index.py", line 11, in <module>
print d['Paul']
KeyError: 'Paul'
注意: 通過 key 訪問 dict 的value,只要 key 存在,dict就返回對應(yīng)的value。如果key不存在,會直接報錯:KeyError。
要避免 KeyError 發(fā)生,有兩個辦法:
一是先判斷一下 key 是否存在,用 in 操作符:
if 'Paul' in d:
print d['Paul']
如果 'Paul' 不存在,if語句判斷為False,自然不會執(zhí)行 print d['Paul'] ,從而避免了錯誤。
二是使用dict本身提供的一個 get 方法,在Key不存在的時候,返回None:
>>> print d.get('Bart')
59
>>> print d.get('Paul')
None
dict的特點
dict的第一個特點是查找速度快,無論dict有10個元素還是10萬個元素,查找速度都一樣。而list的查找速度隨著元素增加而逐漸下降。
不過dict的查找速度快不是沒有代價的,dict的缺點是占用內(nèi)存大,還會浪費很多內(nèi)容,list正好相反,占用內(nèi)存小,但是查找速度慢。
由于dict是按 key 查找,所以,在一個dict中,key不能重復(fù)。
dict的第二個特點就是存儲的key-value序?qū)κ菦]有順序的!這和list不一樣
dict的第三個特點是作為 key 的元素必須不可變,Python的基本類型如字符串、整數(shù)、浮點數(shù)都是不可變的,都可以作為 key。但是list是可變的,就不能作為 key。
dict更新
dict是可變的,也就是說,我們可以隨時往dict中添加新的 key-value。
>>> d['Paul'] = 72
遍歷dict
由于dict也是一個集合,所以,遍歷dict和遍歷list類似,都可以通過 for 循環(huán)實現(xiàn)。
>>> d = { 'Adam': 95, 'Lisa': 85, 'Bart': 59 }
>>> for key in d:
... print key
...
Lisa
Adam
Bart
Set
dict的作用是建立一組 key 和一組 value 的映射關(guān)系,dict的key是不能重復(fù)的。
有的時候,我們只想要 dict 的 key,不關(guān)心 key 對應(yīng)的 value,目的就是保證這個集合的元素不會重復(fù),這時,set就派上用場了。
set 持有一系列元素,這一點和 list 很像,但是set的元素沒有重復(fù),而且是無序的,這點和 dict 的 key很像。
創(chuàng)建 set 的方式是調(diào)用 set() 并傳入一個 list,list的元素將作為set的元素:
>>> s = set(['A', 'B', 'C'])
可以查看 set 的內(nèi)容:
>>> print s
set(['A', 'C', 'B'])
訪問set
由于set存儲的是無序集合,所以我們沒法通過索引來訪問。
訪問 set中的某個元素實際上就是判斷一個元素是否在set中。
>>> 'Bart' in s
True
set的特點
set的內(nèi)部結(jié)構(gòu)和dict很像,唯一區(qū)別是不存儲value,因此,判斷一個元素是否在set中速度很快。
set存儲的元素和dict的key類似,必須是不變對象,因此,任何可變對象是不能放入set中的。
最后,set存儲的元素也是沒有順序的。
set的這些特點,可以應(yīng)用在哪些地方呢?
星期一到星期日可以用字符串'MON', 'TUE', ... 'SUN'表示。
假設(shè)我們讓用戶輸入星期一至星期日的某天,如何判斷用戶的輸入是否是一個有效的星期呢?
如果事先創(chuàng)建好一個set,包含'MON' ~ 'SUN':
weekdays = set(['MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT', 'SUN'])
再判斷輸入是否有效,只需要判斷該字符串是否在set中:
x = '???' # 用戶輸入的字符串
if x in weekdays:
print 'input ok'
else:
print 'input error'
遍歷Set
由于 set 也是一個集合,所以,遍歷 set 和遍歷 list 類似,都可以通過 for 循環(huán)實現(xiàn)。
>>> s = set(['Adam', 'Lisa', 'Bart'])
>>> for name in s:
... print name
...
Lisa
Adam
Bart
更新Set
由于set存儲的是一組不重復(fù)的無序元素,因此,更新set主要做兩件事:
一是把新的元素添加到set中,二是把已有元素從set中刪除。
添加元素時,用set的add()方法:
>>> s = set([1, 2, 3])
>>> s.add(4)
>>> print s
set([1, 2, 3, 4])
如果添加的元素已經(jīng)存在于set中,add()不會報錯,但是不會加進(jìn)去了:
>>> s = set([1, 2, 3])
>>> s.add(3)
>>> print s
set([1, 2, 3])
刪除set中的元素時,用set的remove()方法:
>>> s = set([1, 2, 3, 4])
>>> s.remove(4)
>>> print s
set([1, 2, 3])
如果要刪除的元素不存在,remove()會報錯
>>> s = set([1, 2, 3])
>>> s.remove(4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 4
所以用add()可以直接添加,而remove()前需要判斷。
函數(shù)
調(diào)用函數(shù)
Python內(nèi)置了很多有用的函數(shù),我們可以直接調(diào)用。
要調(diào)用一個函數(shù),需要知道函數(shù)的名稱和參數(shù),比如求絕對值的函數(shù) abs,它接收一個參數(shù)。
可以直接從Python的官方網(wǎng)站查看文檔:
http://docs.python.org/2/library/functions.html#abs
也可以在交互式命令行通過 help(abs) 查看abs函數(shù)的幫助信息。
編寫函數(shù)
在Python中,定義一個函數(shù)要使用 def 語句,依次寫出函數(shù)名、括號、括號中的參數(shù)和冒號:,然后,在縮進(jìn)塊中編寫函數(shù)體,函數(shù)的返回值用 return 語句返回。
def my_abs(x):
if x >= 0:
return x
else:
return -x
請注意,函數(shù)體內(nèi)部的語句在執(zhí)行時,一旦執(zhí)行到return時,函數(shù)就執(zhí)行完畢,并將結(jié)果返回。因此,函數(shù)內(nèi)部通過條件判斷和循環(huán)可以實現(xiàn)非常復(fù)雜的邏輯。
如果沒有return語句,函數(shù)執(zhí)行完畢后也會返回結(jié)果,只是結(jié)果為 None。
return None可以簡寫為return。
返回多值
函數(shù)可以返回多個值嗎?答案是肯定的。
比如在游戲中經(jīng)常需要從一個點移動到另一個點,給出坐標(biāo)、位移和角度,就可以計算出新的坐標(biāo):
math包提供了sin()和 cos()函數(shù),我們先用import引用它:
import math
def move(x, y, step, angle):
nx = x + step * math.cos(angle)
ny = y - step * math.sin(angle)
return nx, ny
這樣我們就可以同時獲得返回值:
>>> x, y = move(100, 100, 60, math.pi / 6)
>>> print x, y
151.961524227 70.0
但其實這只是一種假象,Python函數(shù)返回的仍然是單一值:
>>> r = move(100, 100, 60, math.pi / 6)
>>> print r
(151.96152422706632, 70.0)
用print打印返回結(jié)果,原來返回值是一個tuple!
但是,在語法上,返回一個tuple可以省略括號,而多個變量可以同時接收一個tuple,按位置賦給對應(yīng)的值,所以,Python的函數(shù)返回多值其實就是返回一個tuple,但寫起來更方便。
遞歸函數(shù)
在函數(shù)內(nèi)部,可以調(diào)用其他函數(shù)。如果一個函數(shù)在內(nèi)部調(diào)用自身本身,這個函數(shù)就是遞歸函數(shù)。
舉個例子,我們來計算階乘 n! = 1 * 2 * 3 * ... * n,用函數(shù) fact(n)表示,可以看出:
fact(n) = n! = 1 * 2 * 3 * ... * (n-1) * n = (n-1)! * n = fact(n-1) * n
def fact(n):
if n==1:
return 1
return n * fact(n - 1)
遞歸函數(shù)的優(yōu)點是定義簡單,邏輯清晰。理論上,所有的遞歸函數(shù)都可以寫成循環(huán)的方式,但循環(huán)的邏輯不如遞歸清晰。
使用遞歸函數(shù)需要注意防止棧溢出。在計算機中,函數(shù)調(diào)用是通過棧(stack)這種數(shù)據(jù)結(jié)構(gòu)實現(xiàn)的,每當(dāng)進(jìn)入一個函數(shù)調(diào)用,棧就會加一層棧幀,每當(dāng)函數(shù)返回,棧就會減一層棧幀。由于棧的大小不是無限的,所以,遞歸調(diào)用的次數(shù)過多,會導(dǎo)致棧溢出??梢栽囋囉嬎?fact(10000)。
定義默認(rèn)參數(shù)
定義函數(shù)的時候,還可以有默認(rèn)參數(shù)。
例如Python自帶的 int() 函數(shù),其實就有兩個參數(shù),我們既可以傳一個參數(shù),又可以傳兩個參數(shù):
>>> int('123')
123
>>> int('123', 8)
83
int()函數(shù)的第二個參數(shù)是轉(zhuǎn)換進(jìn)制,如果不傳,默認(rèn)是十進(jìn)制 (base=10),如果傳了,就用傳入的參數(shù)。
可見,函數(shù)的默認(rèn)參數(shù)的作用是簡化調(diào)用,你只需要把必須的參數(shù)傳進(jìn)去。但是在需要的時候,又可以傳入額外的參數(shù)來覆蓋默認(rèn)參數(shù)值。
由于函數(shù)的參數(shù)按從左到右的順序匹配,所以默認(rèn)參數(shù)只能定義在必需參數(shù)的后面:
定義可變參數(shù)
如果想讓一個函數(shù)能接受任意個參數(shù),我們就可以定義一個可變參數(shù):
def fn(*args):
print args
可變參數(shù)的名字前面有個 * 號,我們可以傳入0個、1個或多個參數(shù)給可變參數(shù):
>>> fn()
()
>>> fn('a')
('a',)
>>> fn('a', 'b')
('a', 'b')
>>> fn('a', 'b', 'c')
('a', 'b', 'c')
切片
對list進(jìn)行切片
取一個list的部分元素是非常常見的操作。比如,一個list如下:
>>> L = ['Adam', 'Lisa', 'Bart', 'Paul']
取前3個元素,應(yīng)該怎么做?
笨辦法
>>> [L[0], L[1], L[2]]
['Adam', 'Lisa', 'Bart']
之所以是笨辦法是因為擴展一下,取前N個元素就沒轍了。
取前N個元素,也就是索引為0-(N-1)的元素,可以用循環(huán):
>>> r = []
>>> n = 3
>>> for i in range(n):
... r.append(L[i])
...
>>> r
['Adam', 'Lisa', 'Bart']
對這種經(jīng)常取指定索引范圍的操作,用循環(huán)十分繁瑣,因此,Python提供了切片(Slice)操作符,能大大簡化這種操作。
對應(yīng)上面的問題,取前3個元素,用一行代碼就可以完成切片:
>>> L[0:3]
['Adam', 'Lisa', 'Bart']
L[0:3]表示,從索引0開始取,直到索引3為止,但不包括索引3。即索引0,1,2,正好是3個元素。
如果第一個索引是0,還可以省略:
>>> L[:3]
['Adam', 'Lisa', 'Bart']
只用一個 : ,表示從頭到尾:
>>> L[:]
['Adam', 'Lisa', 'Bart', 'Paul']
因此,L[:]實際上復(fù)制出了一個新list。
切片操作還可以指定第三個參數(shù):
>>> L[::2]
['Adam', 'Bart']
第三個參數(shù)表示每N個取一個,上面的 L[::2] 會每兩個元素取出一個來,也就是隔一個取一個。
把list換成tuple,切片操作完全相同,只是切片的結(jié)果也變成了tuple。
例:
range()函數(shù)可以創(chuàng)建一個數(shù)列:
>>> range(1, 101)
[1, 2, 3, ..., 100]
利用切片,取出:
- 前10個數(shù);
- 3的倍數(shù);
- 不大于50的5的倍數(shù)。
代碼:
L = range(1, 101)
print L[:10]
print L[2::3]
print L[4:50:5]
結(jié)果:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99]
[5, 10, 15, 20, 25, 30, 35, 40, 45, 50]
倒序切片
對于list,既然Python支持L[-1]取倒數(shù)第一個元素,那么它同樣支持倒數(shù)切片,試試:
>>> L = ['Adam', 'Lisa', 'Bart', 'Paul']
>>> L[-2:]
['Bart', 'Paul']
## -2為起始索引到最后
>>> L[:-2]
['Adam', 'Lisa']
## -2為起始索引到最后的基礎(chǔ)上,個數(shù)-2
>>> L[-3:-1]
['Lisa', 'Bart']
## -3為起始索引到最后的基礎(chǔ)上,個數(shù)-1
>>> L[-4:-1:2]
['Adam', 'Bart']
## -3為起始索引到最后的基礎(chǔ)上,個數(shù)-1,并每間隔一個數(shù),過濾一個
記住倒數(shù)第一個元素的索引是-1。倒序切片包含起始索引,不包含結(jié)束索引。
對字符串切片
字符串 'xxx'和 Unicode字符串 u'xxx'也可以看成是一種list,每個元素就是一個字符。因此,字符串也可以用切片操作,只是操作結(jié)果仍是字符串:
>>> 'ABCDEFG'[:3]
'ABC'
>>> 'ABCDEFG'[-3:]
'EFG'
>>> 'ABCDEFG'[::2]
'ACEG'
在很多編程語言中,針對字符串提供了很多各種截取函數(shù),其實目的就是對字符串切片。Python沒有針對字符串的截取函數(shù),只需要切片一個操作就可以完成,非常簡單。
字符串有個upper()方法可以吧字符變?yōu)榇髮懽帜?/p>
迭代
在Python中,如果給定一個list或tuple,我們可以通過for循環(huán)來遍歷這個list或tuple,這種遍歷我們成為迭代(Iteration)。
在Python中,迭代是通過 for ... in 來完成的,而很多語言比如C或者Java,迭代list是通過下標(biāo)完成的,比如Java代碼:
for (i=0; i<list.length; i++) {
n = list[i];
}
因為 Python 的 for循環(huán)不僅可以用在list或tuple上,還可以作用在其他任何可迭代對象上。
因此,迭代操作就是對于一個集合,無論該集合是有序還是無序,我們用 for 循環(huán)總是可以依次取出集合的每一個元素。
注意: 集合是指包含一組元素的數(shù)據(jù)結(jié)構(gòu),我們已經(jīng)介紹的包括:
- 有序集合:list,tuple,str和unicode;
- 無序集合:set
- 無序集合并且具有 key-value 對:dict
而迭代是一個動詞,它指的是一種操作,在Python中,就是 for 循環(huán)。
迭代與按下標(biāo)訪問數(shù)組最大的不同是,后者是一種具體的迭代實現(xiàn)方式,而前者只關(guān)心迭代結(jié)果,根本不關(guān)心迭代內(nèi)部是如何實現(xiàn)的。
索引迭代
Python中,迭代永遠(yuǎn)是取出元素本身,而非元素的索引。
對于有序集合,元素確實是有索引的。有的時候,我們確實想在 for 循環(huán)中拿到索引,怎么辦?
方法是使用 enumerate() 函數(shù):
>>> L = ['Adam', 'Lisa', 'Bart', 'Paul']
>>> for index, name in enumerate(L):
... print index, '-', name
...
0 - Adam
1 - Lisa
2 - Bart
3 - Paul
實際上,enumerate() 函數(shù)把:['Adam', 'Lisa', 'Bart', 'Paul'] 變成了類似[(0, 'Adam'), (1, 'Lisa'), (2, 'Bart'), (3, 'Paul')] 因此,迭代的每一個元素實際上是一個tuple:
for t in enumerate(L):
index = t[0]
name = t[1]
print index, '-', name
如果我們知道每個tuple元素都包含兩個元素,for循環(huán)又可以進(jìn)一步簡寫為:
for index, name in enumerate(L):
print index, '-', name
可見,索引迭代也不是真的按索引訪問,而是由 enumerate() 函數(shù)自動把每個元素變成 (index, element) 這樣的tuple,再迭代,就同時獲得了索引和元素本身。
zip()函數(shù)可以把兩個 list 變成一個 list:
>>> zip([10, 20, 30], ['A', 'B', 'C'])
[(10, 'A'), (20, 'B'), (30, 'C')]
List
生成list
可以用range(1,11)生成List[1,2,3,4,5,6,7,8,10]
>>> range(1, 11)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
但如果要生成[1x1, 2x2, 3x3, ..., 10x10]怎么做?方法一是循環(huán):
>>> L = []
>>> for x in range(1, 11):
... L.append(x * x)
...
>>> L
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
``
但是循環(huán)太繁瑣,而列表生成式則可以用一行語句代替循環(huán)生成上面的list:
```python
>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
這種寫法就是Python特有的列表生成式。利用列表生成式,可以以非常簡潔的代碼生成 list。
寫列表生成式時,把要生成的元素 x * x 放到前面,后面跟 for 循環(huán),就可以把list創(chuàng)建出來,十分有用,多寫幾次,很快就可以熟悉這種語法。
復(fù)雜表達(dá)式
使用for循環(huán)的迭代不僅可以迭代普通的list,還可以迭代dict。
假設(shè)有如下的dict:
d = { 'Adam': 95, 'Lisa': 85, 'Bart': 59 }
完全可以通過一個復(fù)雜的列表生成式把它變成一個 HTML 表格:
tds = ['<tr><td>%s</td><td>%s</td></tr>' % (name, score) for name, score in d.iteritems()]
print '<table>'
print '<tr><th>Name</th><th>Score</th><tr>'
print '\n'.join(tds)
print '</table>'
注:字符串可以通過 % 進(jìn)行格式化,用指定的參數(shù)替代 %s。字符串的join()方法可以把一個 list 拼接成一個字符串。
把打印出來的結(jié)果保存為一個html文件,就可以在瀏覽器中看到效果了:
<table border="1">
<tr><th>Name</th><th>Score</th><tr>
<tr><td>Lisa</td><td>85</td></tr>
<tr><td>Adam</td><td>95</td></tr>
<tr><td>Bart</td><td>59</td></tr>
</table>
條件過濾
列表生成式的 for 循環(huán)后面還可以加上 if 判斷。例如:
>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
如果我們只想要偶數(shù)的平方,不改動 range()的情況下,可以加上 if 來篩選:
>>> [x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]
有了 if 條件,只有 if 判斷為 True 的時候,才把循環(huán)的當(dāng)前元素添加到列表中。
- isinstance(x, str) 可以判斷變量 x 是否是字符串;
- 字符串的 upper() 方法可以返回大寫的字母。
多層表達(dá)式
for循環(huán)可以嵌套,因此,在列表生成式中,也可以用多層 for 循環(huán)來生成列表。
對于字符串 'ABC' 和 '123',可以使用兩層循環(huán),生成全排列:
>>> [m + n for m in 'ABC' for n in '123']
['A1', 'A2', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3']
翻譯成循環(huán)代碼就像下面這樣:
L = []
for m in 'ABC':
for n in '123':
L.append(m + n)