去了趟廈門,剛回來就開始學習了,真是佩服自己呢。廈門這地兒,去一次就夠了,裝13聖地,跟我的風格不是很搭,我主要是去吃的,各種海鮮都炒雞便宜,衝着這個,大概還會再去一趟吧,每家都有團購,真是大衆點評的根據地。好了,言歸正傳,開始學習吧。
第二章 列表和元組
本章開始講數據結構。數據結構是通過某種方式(如編號)組織在一起的數據元素的集合。可以是數字或者字符,也可能是其它數據結構。
Python中最基本的數據結構是序列(sequence)。序列中每個元素都被分配一個序號(即元素的位置,也稱爲索引),第一個是0,第二個是1,依此類推。
2.1 序列概覽
Python有6種內建的序列,本章重點討論最常用的兩種類型:列表和元組。其它序列類型有:字符串,Unicode字符串,buffer對象和xrange對象。
列表跟元組的區別:列表可以修改,元組不能。大多數情況下,列表可以替代元組(也有例外,當元組作爲字典的鍵,因爲鍵不可修改,所以不能用列表)
需要操作一組數據時,序列很好用。可以用序列表示數據庫中一個人的信息,第1個元素是姓名,第2個是年齡,根據上述內容編寫一個列表:
edward=['Edward Gumby',42]
john=['John Smith',50]
database=[edward,john] #結果出現 [['Edward Gumby', 42], ['John Smith', 50]]
Python中還有一個名爲容器(container)的數據結構,它是包含其它對象的任意對象,序列和映射是兩類主要的容器。容器集合(set)既不是序列也是不是映射。2.2 通用序列操作
2.2.1 索引
序列中的都有編號,從0開始遞增,可以通過編號來訪問這些元素
greeting='hello'
greeting[0] #結果顯示第一個元素,'h'
使用負數索引時,是從右邊開始計數,即最後一個。greeting[-1] #結果爲'o',即最後一個元素。
不能超過元素個數範圍
greeting[5] #會報錯,因爲這個位置不存在元素
<pre name="code" class="python">greeting[-6] 同上
如果是調用返回同一個序列,可以直接對返回結果進行索引操作。
fourth=input('year:')[3] #只對輸入年份的末位數字感興趣
year:2005
fourth #結果顯示爲'5'
#根據給定的年月日以數字形式打印出日期
months=[
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
]
#以1~30的數字作爲結尾的列表
endings=['st','nd','rd']+17*['th']\
+['st','nd','rd']+7*['th']\
+['st']
year=input('year:')
month=input('Month(1-12):')
day=input('DAY(1-31):')
month_number=int(month)
day_number=int(day)
#記得要將月份和天數減1,以獲得正確的索引
month_name=months[month_number-1]
ordinal=day+endings[day_number-1]
print(month_name+' '+ordinal+','+year)
2.2.2 分片
分片是訪問一定範圍內的元素,通過冒號相隔的兩個索引來實現。
tag='<a href="http://www.python.org">python web site</a>'
tag[9:30] #結果爲'http://www.python.org',顯示編號9到編號30的元素。
tag[32:-4] #運行結果'python web site',顯示編號32起至倒數第4個元素。
分片的操作需要提供兩個索引作爲邊界,第1個索引的元素是包含在分片內的,第2個不包含。
1.優雅的捷徑
如果需要訪問最後三個,可以有如下操作
numbers=[1,2,3,4,5,6,7,8,9,10]
numbers[3:6] #運行結果[4, 5, 6]
numbers[-3:-1] #這個結果不是想要的,最後一位元素無法顯示,只顯示[8, 9]
numbers[-3:0] #顯示[],如果在分片中最左邊的索引比右邊的晚出現在序列中,結果就是空的序列。
numbers[-3:] #最後一個索引空置就可以出現正確結果了,[8,9,10]
numbers[:3] #同樣適用於序列開始的元素,結果顯示[1,2,3]
numbers[:] #複製整個序列。
#對http://www.something.com形式的URL進行分割
url=input('please enter the URL:')
domain=url[11:-4]
print("domain name:"+domain) #提取域名
2.更大的步長。
步長(step lenth)參數通常是隱匿設置的,在普通的分片中,步長是1,分片操作就是按照這個步長逐個遍歷序列的元素,然後返回開始和結束點之間的所有元素。
numbers=[1,2,3,4,5,6,7,8,9,10] #中間運行了其它程序,所以要重新定義一遍numbers
numbers[0:10:1] #運行結果爲[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],定義了步長爲1
numbers[0:10:2] #運行結果爲[1,3,5,7,9]
numbers[3:6:3] #運行結果爲[4]
numbers[::4] #運行結果爲[1,5,9]
numbers[8:3:-1] #步長可以是負數,即從右向左提取元素,運行結果[9,8,7,6,5]
注意:
- 步長不能爲0
- 開始點的元素(最左邊的)包括在結果之中,結束點的不在
- 當使用負數爲步長時,必須讓開始點(開始索引)大於結束點。
2.2.3 序列相加
通過加號可以進行序列的連接操作,兩種同一類型的序列才能進行連接。
[1,2,3]+[4,5,6,7] #運行結果[1, 2, 3, 4, 5, 6, 7],跟兩個序列元素數量無關
'hello,'+'world!'
"hello,"+'world!'
'hello,world!' #這三個都可以正確顯示'hello,world!'
"hello,"+"1,2,3" #顯示'hello,1,2,3',這裏的1,2,3是字符
[1,2,3]+'hello'#報錯,不是同一類型
2.2.4 乘法
用數字X乘以一個序列會生成新的序列,在新序列中,原來的數列會重複X次。
'python'*5 #運行結果'pythonpythonpythonpythonpython'
[42]*5 #運行結果[42, 42, 42, 42, 42],這裏的[42]是序列而不是數字。
'42'*5 #運行結果'4242424242',這裏的‘42’表示字符串
[1,2,3]*5 #運行結果 [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
None、空列表和初始化
空列表可以用兩個中括號表示[],如果 想要生成一個佔用10個元素的空間,卻不包含任何內容,就要用到None.
[]*5 #運行結果顯示[]
[None]*5 #運行結果[None, None, None, None, None],這裏的None首字母一定要大寫,否則報錯
[]+[] #運行結果[]
[]+[1,2,3] #運行結果[1,2,3]
[]+[None] #運行結果[None]
序列(字符串)乘法示例
#以正確的寬度在居中的“盒子”內打印一個句子
sentence=input("setence:")
screen_width=80
text_width=len(sentence)#?爲什麼
box_width=text_width+6
left_margin=(screen_width-box_width)//2
print
print(' '*left_margin+'+'+'-'*(box_width-6)+ '+') #<span style="color:#6633FF;">修改了原來的語句才合適,版本差異?原來是-2,導致會長一截</span>
print(' '*left_margin+'|'+' '*text_width+'|')
print(' '*left_margin+'|'+sentence+'|')
print(' '*left_margin+'|'+' '*text_width+'|')
print(' '*left_margin+'+'+'-'*(box_width-6)+'+')
print
新版本里面應該有改動,導致按照原語句運行無法形成整齊的方格,原因待研究。2.2.5 成員資格
檢查一個值是否在序列中,可以用in運算符。這個運算符是布爾運算符,檢查條件是否爲真,若爲真(布爾值),返回True,假則返回False。
permissions='rw'
'w' in permissions #運行結果True
's' in permissions #運行結果Falseusers=['mlh','foo','bar']
input('enter your user name:') in users
enter your user name:mlh #運行結果 True
subject='$$$ Get rich now!!! $$$'
'$$$' in subject #運行結果 True
示例,查看用戶輸入的用戶名和PIN碼是否存在於數據庫
#檢查用戶名和PIN碼
database=[
['albert','1234'],
['dilbert','4242'],
['smith','7524'],
['jones','9843']
]
username=input('user name:')
pin=input('PIN code:')
if[username,pin] in database: print ('Access granted')
2.2.6 長度、最小值和最大值
內建函數len,min和max.
Len:返回序列中所包含元素的數量。
min:返回最小的元素
max:返回最大的元素
numbers=[100,34,678]
len(numbers) #序列中共有3個元素,所以返回值爲3
max(numbers) #返回值678
min(numbers) #返回值34
max(2,3) #也可以直接使用,3<pre name="code" class="python">min(9,3,2,5) #返回2
max[2,3] #報錯
2.3 列表:Python的苦力
2.3.1 list函數
字符串不能像列表一樣被修改,根據字符串創建列表很有用。
list('hello') #返回值['h', 'e', 'l', 'l', 'o']
list([1,2,3]) #返回值[1, 2, 3],list函數適用於所有類型的序列
2.3.2 基本的列表操作
1.改變列表:元素賦值
x=[1,1,1]
x[1]=2
x #返回值[1, 2, 1],x已改變
2.刪除元素(del)
names=['Alice','Beth','Cecil','Dee-Dee','Earl']
del names[2]
names #返回值['Alice', 'Beth', 'Dee-Dee', 'Earl'],已刪除索引標記爲2的元素'Cecil'.
3.分片賦值
name=list('Perl')
name #運行結果['P', 'e', 'r', 'l']
name[2:]=list('ar')
name #運行結果['P', 'e', 'a', 'r'],從第3個元素起變成a,r
name[2:]=list('ars')
name #運行結果['P', 'e', 'a', 'r','s'] #長度可以不相等
numbers=[1,5]
numbers[1:1]=[2,3,4] #在第二個位置插入序列
numbers #運行結果[1, 2, 3, 4, 5]
numbers[1:4]=[] #刪除元素
numbers #返回值[1,5]
2.3.3 列表方法
方法是一個與某些對象有緊密聯繫的函數。方法的調用形式爲:對象.方法(參數)
append | 在列表末尾追加新的對象 |
count | 統計某個元素在列表中出現的次數 |
extend | 在列表末尾一次性追加另一個序列中的多個值 |
index | 從列表中找出某個值第一個匹配項的索引位置 |
insert | 將對象插入到列表中 |
pop | 移除列表中的一個元素(默認最後一個),並返回該元素的值 |
remove | 移除列表中某個值的第一個匹配項 |
reverse | 將列表中的元素反向存放 |
reversed | 對一個序列進行反向迭代 |
sort | 在原位置對列表進行排序 |
sorted | 獲取已排序列表副本 |
高級排序 | 按特定方式進行排序 |
1.append
lst=[1,2,3] #第一個字符爲字母l,變量名第一個不能爲數字,也不能用list,一旦用了內建函數作爲變量名,它就不能被調用了
lst.append(4)
lst #返回值[1, 2, 3, 4]
2.count
['to','be','or','not','to','be'].count('to') #'to'在列表中出現的次數,返回2
x=[[1,2],1,1,[2,1,[1,2]]]
x.count(1) #返回值爲2
x.count([1,2]) #返回值爲1
3.extend
a=[1,2,3]
b=[4,5,6]
a.extend(b)
a #返回值[1, 2, 3, 4, 5, 6]
a=[1,2,3]
b.extend(a)
b #返回值[4, 5, 6, 1, 2, 3]
這個用法類似於序列相加,但是序列相加不改變原變量值。如果想要改變變量a的值,需要加上一條a=a+b
也可以用分片賦值,
a=[1,2,3]
b=[4,5,6]
a[len(a):]=b
a #返回[1, 2, 3, 4, 5, 6],分片賦值真是萬能的啊!
4.index
knights=['we','are','the','knights','who','say','ni']
knights.index('who') #返回值4
knights.index('herring') #提示錯誤,herring不在list中
5.insert
numbers=[1,2,3,4,5,6,7]
numbers.insert(3,'four')
numbers #返回值[1, 2, 3, 'four', 4, 5, 6, 7],'four'被插入到索引爲3的位置上
萬能的分片賦值也可以做到。
numbers=[1,2,3,4,5,6,7]
numbers[3:3]=['four']
nmbers #可讀性不如insert。
6.pop
x=[1,2,3]
x.pop() #這裏會先返回值3,默認移除最後一個元素
x #返回值[1, 2],x序列已變。
x.pop(0) #返回值1
x #返回值[2]。pop是唯一一個既能修改列表又返回元素值(除了None)的列表方法
用pop方法可以實現一種常見的數據結構——棧。棧的原則是後進先出(LIFO).棧的操作有兩個,入棧(push)和出棧(pop),python中沒有入棧,可以通過append方法來代替。
x=[1,2,3]
x.append(x.pop())
x #返回值[1, 2, 3],入棧的是剛出棧的值,結果還是原來的棧。
7.remove
x=['to','be','or','not','to','be']
x.remove('be') #沒有返回值,直接修改
x #返回值['to', 'or', 'not', 'to', 'be'],第一個匹配的'be'已經被移除。
x.remove('bee') #報錯,'bee'不存在。
8.reverse
x=[1,2,3]
x.reverse()
x #返回值[3, 2, 1]
如果需要對一個序列進行反向迭代,可以會用reversed函數
x=[1,2,3]
reversed(x) #返回值是<list_reverseiterator object at 0x00000000035D7B70>,reversed函數返回的是一個迭代器對象
list(reversed(x)) #返回值[3, 2, 1],用list函數把它轉換成列表。
9.sort
x=[4,6,2,1,7,9]
x.sort()
x #返回值[1, 2, 4, 6, 7, 9],按順序排列
sort是沒有返回值的,因此下面的做法是錯誤的
x=[4,6,2,1,7,9]
y=x.sort()
print(y) #返回值None,sort沒有返回值
x #返回值[1, 2, 4, 6, 7, 9],被排序了
正確的做法如下
x=[4,6,2,1,7,9]
y=x[:] #先對y賦值,把x列表複製進y
y.sort()
x #返回值[4, 6, 2, 1, 7, 9]
y #返回值[1, 2, 4, 6, 7, 9]
複製整個列表不能用簡單的賦值,
x=[4,6,2,1,7,9]
y=x
y.sort()
x #返回值[1, 2, 4, 6, 7, 9]
y #返回值[1, 2, 4, 6, 7, 9]
獲取已排序列表副本還可以用sorted函數x=[4,6,2,1,7,9]
y=sorted(x)
y #返回值[1, 2, 4, 6, 7, 9]
x #返回值[4, 6, 2, 1, 7, 9]
sorted的返回值總是返回一個列表
sorted('python') #返回值['h', 'n', 'o', 'p', 't', 'y']
10.高級排序
python 3.4中cmp函數已被刪除。
其它的高級排序方法
x=['aardvark','abalone','acme','add','aerate']
x.sort(key=len) #按長度進行排序,如果有長度一樣的單詞,會保持原來位置
x #返回值['add', 'acme', 'aerate', 'abalone', 'aardvark']
x=[4,6,2,1,7,9]
x.sort(reverse=True) #這裏的True首字母必須大寫,否則報錯
x #返回值[9, 7, 6, 4, 2, 1]
2.4 元組:不可變序列
元組也是一種序列,不能修改(字符串也是這樣)。用逗號分隔一些值就自動創造了元組,元組(大部分時候)通過圓括號括起來的,空元組就是()
1,2,3 #返回值(1, 2, 3)
a,b,c #報錯字符必須要用引號
'a','b','c' #返回值('a', 'b', 'c')
42, #返回一個值的元組(42,)
42 #返回42,這不是一個元組
(42) #返回42,也不是元組,創建元組的關鍵在逗號,跟括號無關
3*(40+2) #返回值126,就是數值運算
3*(40+2,) #返回值(42, 42, 42),先進行運算後變成元組
3*(40,+2) #返回值(40, 2, 40, 2, 40, 2)
2.4.1 tuple函數
跟list函數基本一樣:以一個序列作爲參數並把它轉換爲元組。
tuple([1,2,3]) #返回值(1, 2, 3)
tuple('abc') #返回值('a', 'b', 'c')
tuple((1,2,3)) #返回值(1, 2, 3),本身就是元組,返回自身
2.4.2 基本元組操作
元組只有創建元組和訪問元組。
x=1,2,3
x[1] #返回值2,
x[0:2] #返回值(1, 2),元組的分片還是元組
2.4.3 那麼,意義何在
大部分時候,列表可以滿足對序列的所有需求。由於以下兩個原因,元組無可替代
- 元組可以在映射(和集合的成員)中當作鍵使用,列表不行
- 元組作爲很多內建函數和方法的返回值存在。