相信你已經(jīng)接觸過C語言中數(shù)組的概念坛掠。類似C語言中的數(shù)組,Python中有序列的概念治筒。序列是一個集合概念屉栓,即,你可以把它理解成泛指Python中一些數(shù)據(jù)的集合耸袜,對于這些數(shù)據(jù)集合系瓢,其數(shù)據(jù)存儲是有先后順序的,你可以按順序取出其中的每一個元素句灌。例如夷陋,字符串是一個序列欠拾,對字符串name可以執(zhí)行下面的操作
for c in name:
print(c)
你猜猜它的運行結(jié)果是什么?
Python中的序列包括字符串骗绕,元組藐窄,列表,前面我們已經(jīng)介紹過字符串酬土,下面讓我們了解一下列表和元組荆忍。
5.1 列表
C語言中的數(shù)組是一組固定數(shù)量的同種類型元素的集合。比如撤缴,下面的語句定義了兩個數(shù)組:
int a[10]; // 定義一個int型定長數(shù)組刹枉,含10個int元素
Int b[ ]={ 1, 2, 3, 4 }; // 用可變長方式定義一個數(shù)組,
// 元素類型和數(shù)組長度根據(jù)給出的值猜測
// 此處是一個含4個int元素的數(shù)組屈呕,定義時可變長微宝,
// 定義好后就變?yōu)槎ㄩL
我們知道,C語言中的數(shù)組有很大的局限性:
- 首先虎眨,它的元素類型必須相同蟋软,比如,int類型數(shù)組元素不能存放字符串類型元素
- 其次嗽桩,它是定長的岳守,我們不能運行時改變它的長度,即不能運行時向它添加或刪除元素
Python中的列表解決了以上兩個問題碌冶,首先湿痢,Python中的列表可以存儲任意類型的對象;其次扑庞,Python中的列表可以在運行時添加或刪除元素譬重。
5.1.1 創(chuàng)建列表
1. 創(chuàng)建一個空列表
以下兩種方式都可以創(chuàng)建一個空列表:
L1=list() # 調(diào)用列表類型的默認構(gòu)造函數(shù),可以創(chuàng)建一個空列表
L2=[ ] # [ ]表示一個空列表嫩挤,直接將它賦給一個變量即可
2. 創(chuàng)建一個含有元素的列表
L3 = [ 1, 2, 3 ] # 中括號中用逗號分隔元素害幅,即可創(chuàng)建一個含有元素的列表
L4 = list("Jack") # 把另一個序列作為參數(shù)傳遞給列表類型的構(gòu)造函數(shù)消恍,
# 就可創(chuàng)建一個含有元素的列表
# 你可以查看一下這個代碼的結(jié)果
構(gòu)造函數(shù)是面向?qū)ο蟪绦蛟O(shè)計中岂昭,為某個類定義的用于創(chuàng)建類實例的函數(shù)。使用它可以憑空( 使用不帶參數(shù)或帶默認參數(shù)的默認構(gòu)造函數(shù) )創(chuàng)建一個該類的實例狠怨,或通過調(diào)用帶參數(shù)的構(gòu)造函數(shù)约啊,用參數(shù)指定的值構(gòu)造一個類實例,其中的參數(shù)說明了該類實例的屬性佣赖。
3. 列表的元素可以是任意類型
L1=[ 1, 2, 3, 4] # 元素類型相同沒有問題
L2=[ 1, 2, "Jack"] # 元素類型不同毫無壓力
L3=[ 1,2, 3, [4, 5] ] # 元素可以是復合類型
def adder(x, y):
return x+y
def multiplier(x, y):
return x*y
def divider(x, y):
return x/y
def remainder(x, y):
return x%y
L_func=[adder, multiplier, divider, remainder] # 元素甚至可以是函數(shù)
x=1,y=3
for func in L_func:
print(func(x, y)) # 在C語言中也能實現(xiàn)這個功能恰矩,但要復雜得多
# 在GUI程序設(shè)計中,這個功能對于簡化同一菜單下不
# 同菜單項的處理代碼具有很好的作用
5.1.2 下標操作和切片
在字符串那一章中憎蛤,我們看到了對字符串可以執(zhí)行下標操作得到指定下標處的字符外傅,以及使用切片得到子字符串纪吮。對列表也可以使用類似的操作:
>>> L=["Jack","Jane","Henry"]
>>> L[0]
"Jack" # 下標從0開始計算
>>> L[0][2] # L[0]得到"Jack", 對它可以再次運用
# 下標操作,得到結(jié)果為'c'
'c'
>>> L[-1] # 可以使用負下標萎胰,負下標從-1開始計算
# 可以把列表想象成元素按順序從左到右排列碾盟,
# 從最左邊開始計算下標時從0開始
# 從最右邊開始計算下標時從-1開始
"Henry"
>>> L[0:2] # 切片時,冒號左側(cè)下標位置包含在內(nèi)技竟,
# 冒號右側(cè)下標位置排除在外
["Jack", "Jane"]
>>> L[-2: ] # 可以使用負下標冰肴,省略冒號右側(cè)的數(shù)字,
#表示截取到包括尾部元素在內(nèi)的元素
["Jane", "Henry"]
>>> L[:2] # 省略冒號左邊的數(shù)字榔组,表示從包括
# 頭部元素開始的位置截取和L[0:2]結(jié)果相同
['Jack', 'Jane']
>>> L[-2, -1] # 這樣不能截取到最后一個下標所在的元素熙尉,
# 因為它不包括在內(nèi)
["Jane"]
>>> L[0, -1] # 可以混合使用正下標和負下標
['Jack', 'Jane']
5.1.3 列表解析
對于序列,可以使用一個稱為列表解析東東搓扯,通過對原始序列進行變換检痰,得到我們想要的一個列表:
>>> L=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> L2=[ i*2 for i in L ]
>>> L2
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
>>> L3=[ i for i in L2 if i%2==0 ] # 可以應用條件語句進行選擇
>>> L3
[2, 4, 6, 8, 10]
5.1.4 動態(tài)添加或刪除元素
列表有多個成員函數(shù)( 或稱方法 )可用于向列表中動態(tài)添加元素,我們常用的是向列表尾部添加元素擅编,這需要調(diào)用列表的append( ) 方法:
>>> L=[]
>>> L.append(1) # append是一個函數(shù)攀细,通過L.appned(...)的形式調(diào)用
>>> L.append(2) # 說明它是定義在列表類中的一個成員函數(shù),
>>> L.append(3) # 而不是一個普通的全局函數(shù),在全局范圍內(nèi)不存在這個函數(shù)
# 它只能通過一個列表對象(或稱變量)+.append(...)的形式調(diào)用
>>> L
[1, 2, 3]
刪除元素可以使用.pop( ) 方法爱态,該方法從列表對象尾部彈出一個元素谭贪,并將該元素的值作為返回值返回。
>>> L=[1, 2, 3]
>>> a=L.pop() # a==3
>>> L
[1, 2]
>>> b=L.pop() # b==2
>>> L
[1]
>>> c=L.pop() # c==1
>>> L
[] # 現(xiàn)在列表L為空
名字的作用域
計算機代碼中的名字锦担,包括類名俭识、函數(shù)名、變量名等都有作用域洞渔,可以簡單地把它理解為它在程序中可見并且起作用的范圍套媚。
首先看全局作用域: 在所有函數(shù)和類外部定義的名字具有全局作用域,它從定義它的位置開始可見并起作用磁椒;然后看一下函數(shù)作用域堤瘤,只在函數(shù)內(nèi)部起作用的變量稱為具有函數(shù)作用域,函數(shù)結(jié)束則該作用域結(jié)束浆熔。
name="Jack" define printName(): global name # 不像C語言本辐,Python語言在局部作用域,如函數(shù)內(nèi)部医增,必須 # 使用global聲明一下全局變量的名字慎皱,才能使用它 print(name) define printInnerName(): name="Henry" # 這個name的變量名和全局變量的名字相同,但 # 具有局部作用域叶骨,它可以看做另一個僅在 # 該函數(shù)內(nèi)部可見并可用的變量茫多,外部的name變量 # 被它屏蔽了,到該函數(shù)結(jié)束忽刽,它的作用域結(jié)束 # 這被稱為具有函數(shù)作用域 print(name) print(name) # 請問打印的是哪個變量,全局的天揖,還是printInnerName()中的
類作用域是僅用于面向?qū)ο蟪绦蛟O(shè)計中的類所應用的作用域夺欲,還記得我們討論過類和對象的聯(lián)系和區(qū)別嗎? 實際上,面向?qū)ο蟪绦蛟O(shè)計是給對象添加表示對象狀態(tài)的屬性變量以及該類對象可以執(zhí)行的操作今膊。
比如洁闰,一支筆具有墨水顏色、墨水容量万细、筆殼顏色扑眉、有無筆帽、有無按鈕等屬性赖钞,它是通過使用類中定義變量的形式實現(xiàn)的腰素;也有更換筆芯、用筆書寫等操作雪营,對象的操作也稱對象的方法弓千,對象的操作是通過在類中定義函數(shù)實現(xiàn)的:
# 我們的自定義類相當于Python語言的內(nèi)置類型, # 我們將創(chuàng)建一個類的對象(或稱變量)稱為實例化一個對象 # 類的實例化是通過調(diào)用類的__init__(...)方法得到的 # 類中的函數(shù)稱為方法献起,這是面向?qū)ο蟪绦蛟O(shè)計的術(shù)語 # 類中可以有函數(shù)名相同洋访,但參數(shù)數(shù)量不同的函數(shù),從語義上講谴餐,這些同名函數(shù)的作用應該是相似的 # 這些同名但參數(shù)數(shù)量不同的函數(shù)形成了函數(shù)的重載姻政, # 函數(shù)重載的作用是采用不同的方式完成相似的任務 # 比如,對于類的構(gòu)造函數(shù)來說: # 要制作一支筆岂嗓,可以用另外一支筆作為模板 # def __init__(self, pen=pen): # something # 也可以直接指定筆芯汁展、筆殼顏色,重新制作一支筆: # biXin=BiXin() # def __init__(self, biXin=biXin, shellColor="white"): # something class BiXin(object) { # 每個類中都有__init__()函數(shù)厌殉,它是一個特殊的函數(shù)食绿, # 它必須定義,用于創(chuàng)建一個該類的對象 def __init__(self, color="black", amount=10): # 類的每個成員函數(shù)第一個參數(shù)都必須是self # 它表示所討論的變量本身公罕,它是一個隱含參數(shù)器紧,調(diào)用時不需指定 # 它就是調(diào)用該函數(shù)時.左側(cè)的對象名 # 上面用默認函數(shù)指定默認筆芯的油墨顏色為black,油墨量為10 # 用不同的油墨顏色和油墨量作為參數(shù)調(diào)用該函數(shù)可以創(chuàng)建不同的筆芯 self.color=color # self.color是對象的屬性楼眷, # 等號右側(cè)的color是構(gòu)造函數(shù)中傳入的參數(shù) self.amount=amount # 含義相似 } class Pen(object) { # BiXin()調(diào)用BiXin類的__init__()構(gòu)造函數(shù)創(chuàng)建了一個默認筆芯 # 它不帶參數(shù)铲汪,但由于定義該函數(shù)時使用了默認參數(shù),實際上它的參數(shù)是: # color="black" , amount=1000 def __init__(self, biXin=BiXin(), shellColor='white'): self.biXin=biXin self.shellColor=shellColor def changeBiXin(self, biXin=BiXin()): self.biXin=biXin def write(self): # 調(diào)用一次write()摩桶,筆芯油墨量減1 print("writing sth.") self.amount-=1 if(self.amount==0): print("筆芯用光了桥状,請更換筆芯") } # 下面使用上面的類創(chuàng)建一些對象帽揪,并且使用它們 biXinDefault=BiXin() biXinRed=Bixin(color="red") biXinBlackSmall=BiXin(color='black', amount=500) biXinRedLarge=BiXin(color='red', amount=2000) pen1=Pen() # 默認筆芯硝清,默認筆殼顏色 pen2=(biXin=biXinRed) # 紅色筆芯,默認筆殼顏色 pen2.changeBixin(biXinDefault) # 更換筆芯 for i range(0, 10): pen2.write() # 輸出10次 "writing sth." # 輸出1次"筆芯用光了转晰,請更換筆芯"
現(xiàn)在你能猜猜如何理解類作用域和對象作用域了嗎?
5.2 元組
下面講元組芦拿,你可以將元組理解成不可變的列表士飒,除了不能修改元素項以外,元組支持和列表相似的大部分方法蔗崎。
Python中酵幕,元組是用小括號括起來的用逗號分隔的元素集合。
t1=(1, 2, 3, 4, 5)
L=[1, 2, 3, 4, 5]
t2=tuple(L) # tuple是元組的意思缓苛,它將序列L轉(zhuǎn)換成元組
請你用python的help()芳撒、dir()探索一下元組支持的方法。
5.3 元組的用法
5.3.1 用在print函數(shù)中
使用格式字符串對輸出進行格式化
Python3的print( ) 函數(shù)支持傳統(tǒng)的格式字符串未桥,這和C語言中的printf( )函數(shù)支持的格式字符串相似笔刹。所謂格式字符串也是一個字符串,其中既有常規(guī)輸出的字符串冬耿,也嵌入了一些格式字符舌菜,當print()輸出時碰到該格式字符時,會用格式字符串后面的變量列表中對應位置的變量替換該格式字符輸出亦镶,其輸出格式由該格式字符指定日月。如:
# welcome.py names=("Jack", "Jane", "Henry") for name in names: print("%s: welcome!" % name) # %s表示用字符串內(nèi)容替換這個格式字符 # 第二個%前面的字符串就是格式字符串 # 它后面的是等待輸出的變量 # 你猜這段程序的輸出是什么 # 這段代碼可用作應用程序的登錄代碼, # 不同的賬號登錄后缤骨,顯示針對性的消息
答案:
$ python3 welcome.py Jack: welcome! Jane: welcome! Henry: welcome!
當我們需要使用格式字符串輸出多個變量時爱咬,可不可以呢? 比如下面的代碼:
# welcome2.py
names=("Jack", "Jane", "Henry")
places=("home","school","store","play ground")
L=list(zip(names,places)) # zip 函數(shù)把names和places中的元素兩兩組合
# list()把zip()的返回值轉(zhuǎn)換成一個列表,形如
# [("Jack","home"), ("Jack", "school") ...]
# 我們看到這個列表的每個元素是一個二元組
for name, place in L:
print("%s: welcome to the %s" % name, place) # 請問這樣行不行呢
答案是不行绊起。這是因為print( )中的逗號把它前后的內(nèi)容分成了兩個部分台颠,這兩個部分分別看作print()的一個參數(shù),print()將分別輸出這兩個參數(shù)勒庄,但第一個參數(shù)的格式字符串要求輸出兩個變量串前,但這個參數(shù)沒有提供第二個變量,只有name实蔽。
這時荡碾,需要我們用元組把name和place組合起來,作為格式字符串的待輸出變量局装。上面代碼改成:
print("%s: welcome to the %s" % (name, place)) # 這樣就行了坛吁,輸出多個變量時
# 就用多元組
你運行一下這段程序,看看輸出結(jié)果是什么?
5.3.2 用作函數(shù)的返回值
通常函數(shù)的返回值只是一個值铐尚,可以是整數(shù)拨脉、浮點數(shù)、字符串等宣增,但只有一個玫膀。使用Python中的高級數(shù)據(jù)類型,可以起到將返回值擴展為多個的作用爹脾。由于元組是不可變的帖旨,而我們通常不希望改變函數(shù)的返回值箕昭,所以二元組或多元組常常是函數(shù)返回值的優(yōu)質(zhì)選項。
知識點: 元組的解包
下面的代碼解阅,將元組解包落竹,把它里面的元素值賦給單個的變量:
t=(1,2) i, j = t # 經(jīng)此賦值后,i=1, j=2 货抄,這種形式對多元組也適用 print(i, j)
下面是的函數(shù)求取斐波那契數(shù)列第n位和第n+1位的數(shù)字:
def fib(n=0):
if n > 0: # fib(n)
i, j = fib(n-1)
return((j, i+j))
else # fib(0)
return(0, 1)
print(fib(10)) # n=10
下面解釋這段代碼述召,這段代碼運用了兩個技術(shù)
-
一是遞歸函數(shù)
知識點: 遞歸函數(shù)
遞歸函數(shù)是在代碼中調(diào)用了函數(shù)自身的函數(shù)。比如蟹地,此處求fib(n)用到了fib(n-1)的結(jié)果桨武,就調(diào)用fib(n-1),然后用其結(jié)果計算fib(n)锈津,再把這個計算結(jié)果作為返回值返回呀酸。想象一下,fib(n-1)是一個中間值琼梆,還要對它進行計算性誉,因此,要繼續(xù)展開茎杂,求fib(n-1)要用到fib(n-2)的結(jié)果错览,逐層遞歸,直到fib(0)煌往,而fib(0)有確切的結(jié)果倾哺,即(0, 1),遞歸展開至此刽脖,計算結(jié)束羞海。
根據(jù)上述分析,遞歸函數(shù)有兩個要點曲管。一是計算第n項時的通項如何用代碼表示却邓,二是計算到起點時(即第1項時),對起點有確定的結(jié)果院水,不可再用通項表示腊徙。
二是將二元組作為函數(shù)的返回值,這很好理解
假如我們想要只求斐波那契數(shù)列的第n項數(shù)字檬某,可以把代碼改成:
def fib(n=0):
if n > 1:
i, j = fib(n-2), fib(n-1) # 第n項為通項
return (i+j)
elif n== 1: # 第1項和第0項是邊界撬腾,它們不能用通項求取
return 1
else:
return 0