如果你發(fā)現(xiàn)特殊情況太多,那很可能是用錯算法了液斜。
—— Carig Zerouni
目錄
前幾節(jié)我們介紹了Python 中四種數(shù)據(jù)結構的特性和基本用法累贤,本節(jié)介紹與數(shù)據(jù)結構相關的高級特性。
- 序列
- 迭代器
- 列表生成式
- 生成器
- 強制類型轉換
1少漆,序列
Python 序列是指臼膏,其中存放的元素是有序排列
的,可用下標訪問示损,字符串
渗磅,列表
,元組
都是序列检访。
而字典
與集合
中的元素是無序排列的始鱼,因此一般不歸在序列
中。
Python 序列有如下特點:
- 序列中的元素是
不可變
類型 - 序列中的元素可用
下標
訪問脆贵,下標可正可負 - 可通過
切片
訪問部分連續(xù)
元素 - 可進行
相加
风响,相乘
,in 運算
- 可通過
for 循環(huán)
遍歷所有元素
可以使用collections
模塊中的Sequence
類來查看一個對象是否是一個序列:
>>> isinstance('', collections.Sequence) # 字符串是序列
True
>>> isinstance([], collections.Sequence) # 列表是序列
True
>>> isinstance((), collections.Sequence) # 元組是序列
True
>>> isinstance({}, collections.Sequence) # 字典不是序列
False
>>> isinstance(set(), collections.Sequence) # 集合不是序列
False
提示:
1丹禀,
isinstance
函數(shù)用于查看一個對象屬于某個類2状勤,在使用
模塊
時,要先import
該模塊
2双泪,迭代器
可迭代類型
我們知道str
持搜,list
,tuple
焙矛,dict
葫盼,set
都可用for 循環(huán)
來遍歷,這個遍歷的過程就是一個迭代
過程村斟,這些類型都是可迭代
類型贫导。
可迭代的類型,都實現(xiàn)了__iter__
方法蟆盹,我們通過dir(可迭代對象)
孩灯,可以看到,可迭代對象的魔法方法
中都有一個__iter__
方法逾滥。
我們也可以通過collections
模塊中的Iterable
類型來查看一個對象是不是可迭代對象:
>>> isinstance('', collections.Iterable)
True
>>> isinstance([], collections.Iterable)
True
>>> isinstance((), collections.Iterable)
True
>>> isinstance({}, collections.Iterable)
True
>>> isinstance(set(), collections.Iterable)
True
迭代器
迭代器
是一種可迭代
的對象峰档。
迭代器一定是可迭代的,可迭代的對象不一定是迭代器。
迭代器要實現(xiàn)兩個魔法方法:__iter__
和 __next__
讥巡。
通過collections
模塊中的Iterator
類型來查看這兩個方法:
>>> dir(collections.Iterator)
判斷一個對象是不是迭代器:
>>> isinstance('', collections.Iterator) # 字符串不是迭代器
False
>>> isinstance([], collections.Iterator) # 列表不是迭代器
False
>>> isinstance((), collections.Iterator) # 元組不是迭代器
False
>>> isinstance({}, collections.Iterator) # 字典不是迭代器
False
>>> isinstance(set(), collections.Iterator) # 集合不是迭代器
False
迭代器通用函數(shù)
迭代器有一些通用函數(shù)掀亩,下面我們介紹一些常用的。
1.enumerate
函數(shù)
在Python3 中欢顷,enumerate
實際上是一個類
槽棍,可通過help(enumerate)
查看,也可以把它當做函數(shù)來使用抬驴。
其經常被用在for 循環(huán)
中刹泄,即可遍歷下標,又能遍歷數(shù)據(jù)怎爵。
作用: 用于給一個
可迭代
的對象特石,添加下標
原型: enumerate(iterable[, start]) -> iterator
參數(shù) iterable: 一個可迭代的對象
參數(shù) start: 下標起始位置
返回值: 一個enumerate
對象,同時也是一個迭代器
示例:
>>> l = enumerate(['a', 'c', 'b']) # 參數(shù)是一個列表
>>> type(l)
<class 'enumerate'>
>>> isinstance(l, collections.Iterator) # 是一個迭代器
True
>>> for index, item in l: # for 循環(huán)遍歷鳖链,能遍歷出下標
... print(index, item)
...
0 a
1 c
2 b
2.iter
函數(shù)
作用:將一個可迭代的序列
iterable
轉換成迭代器
原型:iter(iterable) -> iterator
參數(shù):iterable 是一個可迭代的序列
返回值:一個迭代器
示例:
>>> iter('123') # 參數(shù)是字符串
<str_iterator object at 0x7fcb7dd320b8> # str 迭代器
>>> iter([1, 2, 3]) # 參數(shù)是列表
<list_iterator object at 0x7fcb7dd4a0b8> # list 迭代器
>>> iter((1, 2, 3)) # 參數(shù)是元組
<tuple_iterator object at 0x7fcb7dd4a0b8> # tuple 迭代器
>>> iter(set([1, 2, 3])) # 參數(shù)是集合
<set_iterator object at 0x7fcb7d2c5e10> # set 迭代器
>>> iter({'a':1, 'b':2}) # 參數(shù)是字典
<dict_keyiterator object at 0x7fcb7f467098> # dict 迭代器
3.next
函數(shù)
作用:返回迭代器的下一個元素
原型:next(iterator[, default]) -> item
參數(shù) iterator:是一個迭代器類型
參數(shù) default:任意類型數(shù)據(jù)姆蘸,可省
返回值:當
迭代器中有元素
時:返回迭代器中的下一個元素
當迭代器中沒有元素
且沒有default 參數(shù)
時:拋出StopIteration
異常
當迭代器中沒有元素
且有default 參數(shù)
時:返回default
示例:
>>> i = iter([1, 3, 5]) # i 是一個迭代器
>>> next(i) # 返回 1
1
>>> next(i) # 返回 3
3
>>> next(i) # 返回 5
5
>>> next(i) # i 中沒有元素,拋出異常
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>
>>> next(i, 7) # i 中沒有元素芙委,返回第二個參數(shù) 7
7
4.len
函數(shù)
作用:用于計算一個對象
obj
中的元素的個數(shù)
原型:len(obj, /)
參數(shù):一般obj
是一個可迭代類型對象逞敷,實際上,只要實現(xiàn)了__len__
方法的對象灌侣,都可以使用該函數(shù)
返回值:一個整數(shù)
示例:
>>> len('abc')
3
>>> len([1, 2, 3])
3
5.max
函數(shù)
作用:返回可迭代對象
iterable
中的最大元素
原型:max(iterable)
參數(shù):iterable
是一個可迭代的對象推捐,并且iterable
中的元素可比較
返回值:最大值
示例:
>>> max([1, 2])
2
>>> max([1, 2, 3])
3
>>> max('b', 'a')
'b'
>>> max('abc')
'c'
>>> max(1, 'a') # 整數(shù)與字符串不是同類型,不可比較
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '>' not supported between instances of 'str' and 'int'
6.min
函數(shù)
作用:返回可迭代對象
iterable
中的最小元素
原型:min(iterable)
參數(shù):iterable
是一個可迭代的對象侧啼,并且iterable
中的元素可比較
返回值:最小值
示例:
>>> min([1, 2])
1
>>> min([2, 3])
2
>>> min('abc')
'a'
>>> min('b', 'c')
'b'
>>> min('b', 2) # 整數(shù)與字符串不是同類型牛柒,不可比較
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'int' and 'str'
7.sum
函數(shù)
作用:計算可迭代對象
iterable
中的數(shù)據(jù)之和,最后在加上start
原型:sum(iterable, start=0, /)
參數(shù):iterable
是一個可迭代對象痊乾,其中的元素是數(shù)字類型
返回值:所有元素之和
示例:
>>> sum([1, 2, 3]) # 計算 1皮壁,2,3 之和
6
>>> sum([1, 2, 3], 5) # 計算 1哪审,2蛾魄,3 之和,再加上 5
11
8.reversed
函數(shù)
reversed
實際上是一個類湿滓,可用help(reversed)
查看滴须。
作用:將一個序列
sequence
反轉
原型:reversed(sequence)
參數(shù):sequence
是一個序列類型
返回值:一個reversed
對象,該對象也是一個迭代器
叽奥,可被迭代
示例:
>>> r = reversed('abcde')
>>> r # 一個 reversed 對象
<reversed object at 0x7fcb79970518>
>>> isinstance(r, collections.Iterator) # 也是一個迭代器
True
>>> [i for i in r] # 轉換成列表扔水,查看其中的元素
['e', 'd', 'c', 'b', 'a']
>>>
>>> r = reversed([1, 3, 5, 7])
>>> [i for i in r]
[7, 5, 3, 1]
3,列表生成式
列表生成式
而线,又叫列表推導式
铭污,用于從一個可迭代對象
生成一個列表
,它是一種代碼簡寫形式膀篮,其優(yōu)點是代碼簡潔優(yōu)雅嘹狞。
比如,我們有一個列表 [1, 3, 5]
誓竿,想求其中每個元素的平方磅网,再將結果放入列表中,最終的結果是[1, 9, 25]
筷屡。
如果是一般的方式涧偷,我們寫出來的代碼是這樣的:
l = [1, 3, 5]
l2 = []
for i in l:
item = i * i
l2.append(item)
print(l2)
如果用列表生成式的方式,代碼是這樣的:
l = [1, 3, 5]
l2 = [i * i for i in l]
print(l2)
可以看到列表生成式比普通的形式要簡潔許多毙死。
列表生成式語法
最簡單的列表生成式的語法燎潮,就像上面的代碼一樣:
列表生成式
由三部分組成:
- 列表符號:中括號
[]
- 表達式:用于生成新列表中的每個元素,一般與
item
有關扼倘,也可無關 - for 循環(huán):用于迭代原始
可迭代對象
列表生成式中的if
判斷
列表生成式中也可以有if
判斷确封,當判斷條件
成立時,才會執(zhí)行表達式再菊,并將該表達式的結果append
到新的列表中爪喘。
這里的if
判斷沒有else
部分,判斷條件
一般與item
有關纠拔。
如下:
示例:
l = [1, 3, 5]
# 只有當 l 中的元素大于 1 時秉剑,才算平方
l2 = [i * i for i in l if i > 1]
print(l2)
range
函數(shù)
在Python2.x 中
,range
是一個函數(shù)
稠诲。
在Python3.x
中侦鹏,range
是一個類
,可用help(range)
查看其手冊臀叙。
>>> range
<class 'range'>
下面介紹Python3.x
中range
的用法种柑,有兩種參數(shù)形式:
作用:生成一個從
start
到stop
的,步長為step
的匹耕,可迭代的整數(shù)序列聚请,該序列包含start
,不包含stop
稳其,即遵循左開右閉
原則
原型:range(stop) -> range object
range(start, stop[, step]) -> range object參數(shù):
當只有
stop
參數(shù)時驶赏,該序列從0
開始到stop
,步長為1
當有start
和stop
參數(shù)時既鞠,該序列從start
開始到stop
煤傍,步長為1
當有step
參數(shù)時,步長為step
返回值:一個
range
對象
示例:
>>> range(5)
range(0, 5)
>>> range(1, 5)
range(1, 5)
>>> range(1, 5, 2)
range(1, 5, 2)
range
對象是一個序列嘱蛋,而不是一個迭代器:
>>> isinstance(range(5), collections.Sequence)
True
>>> isinstance(range(5), collections.Iterator)
False
可以使用列表生成式
來查看range
中的內容:
>>> [i for i in range(5)] # 從 0 到 5
[0, 1, 2, 3, 4]
>>> [i for i in range(1, 5)] # 從 1 到 5
[1, 2, 3, 4]
>>> [i for i in range(1, 5, 2)] # 步長為 2
[1, 3]
4蚯姆,生成器
生成器也是一個迭代器
五续。生成器跟列表有點像,但優(yōu)點是比列表節(jié)省內存
龄恋。
對于列表疙驾,Python 會為列表中的每個元素都分配實實在在的內存空間,如果列表中的元素很多郭毕,那么列表將消耗大量內存它碎。
而對于生成器,Python 并不會為其中的每個元素都分配內存显押。
生成器記錄的是一種算法扳肛,是如何生成數(shù)據(jù)的算法,在每次用到數(shù)據(jù)時乘碑,才會去生成數(shù)據(jù)挖息,而不會一開始就將所有的數(shù)據(jù)準備好。
因此,對于相同的功能,生成器
和列表
都能完成邻辉,而生成器可以節(jié)省大量的內存。
創(chuàng)建生成器有兩種方式:
- 將
列表生成式
中的中括號[]
改為小括號()
- 在函數(shù)中使用
yield
關鍵字
使用列表生成式
如下代碼可以生成一個列表:
>>> [i for i in range(5)]
[0, 1, 2, 3, 4]
將中括號[]
改為小括號()
沉迹,就是一個生成器:
>>> l = (i for i in range(5))
>>> l
<generator object <genexpr> at 0x7f3433d2d9e8>
>>> type(l)
<class 'generator'>
>>> isinstance(l, collections.Iterator) # 生成器也是一個迭代器
True
其中的generator
就是生成器的意思,它也是一個類
害驹。
使用yield
關鍵字
比如鞭呕,我們想計算列表[1, 3, 5]
中每個元素的平方,使用yield
關鍵字宛官,代碼如下:
#! /usr/bin/env python3
def test():
print('test...')
l = [1, 3, 5]
for i in l:
tmp = i * i
print('yield tmp:%s' % tmp)
yield tmp
t = test()
print(t) # <generator object test at 0x7fde1cdaa3b8>
print(type(t)) # <class'generator'>
注意葫松,我們定義了一個函數(shù),這里我們只是為了演示如何使用yield
來創(chuàng)建生成器底洗,而不用過多關注如何定義函數(shù)腋么。
函數(shù)
的概念我們會在后續(xù)章節(jié)詳細介紹。
執(zhí)行以上代碼亥揖,輸出如下:
<generator object test at 0x7fde1cdaa3b8>
<class'generator'>
你會發(fā)現(xiàn)珊擂,字符串test...
并沒有被打印出來。
你可能會有疑問费变,既然代碼t = test()
已經執(zhí)行了摧扇,那整個test()
函數(shù)中的代碼都應該執(zhí)行完了才對,那字符串test...
怎么會沒有打印呢挚歧?
那是因為扛稽,生成器
中代碼的執(zhí)行是惰性
的。當執(zhí)行t = test()
這行代碼時滑负,test()
函數(shù)并沒有被執(zhí)行在张。
前邊我們說過用含,生成器記錄的是一個算法
,而不是真正的數(shù)據(jù)帮匾,數(shù)據(jù)只有當使用到的時候啄骇,才會去生成。
所以辟狈,變量 t
中只是一個算法肠缔,而沒有數(shù)據(jù)夏跷。
因為哼转,生成器也是一個迭代器,所以生成器可以使用next()
函數(shù)來訪問其中的數(shù)據(jù):
i = next(t)
print('i value is', i)
執(zhí)行上面這行代碼后槽华,程序會輸出:
test...
yield tmp:1
i value is 1
字符串test...
被打印壹蔓,說明test()
執(zhí)行了。
當代碼執(zhí)行到yield
時猫态,變量i
會接收到yield
返回的數(shù)據(jù)佣蓉,此時,代碼會從yield
處跳出test()
函數(shù)亲雪。
如果接下來勇凭,不再遍歷變量t
中的數(shù)據(jù),那么整個代碼就執(zhí)行結束了义辕。
如果我們再次執(zhí)行代碼:
j = next(t)
print('j value is', j)
程序會輸出:
yield tmp:9
j value is 9
可見代碼會在上次yield
的地方虾标,再次向下執(zhí)行。
我們再次執(zhí)行代碼:
k = next(t)
print('k value is', k)
程序會輸出:
yield tmp:25
k value is 25
當t
中的元素被遍歷完后灌砖,如果再次執(zhí)行next(t)
璧函,則會拋出StopIteration
異常。
使用next()
函數(shù)來遍歷生成器中的所有元素是很麻煩的基显,我們可以像遍歷列表一樣蘸吓,用for 循環(huán)
來遍歷生成器中的元素:
for i in t:
print(i)
輸出如下:
test...
yield tmp:1
1
yield tmp:9
9
yield tmp:25
25
整個遍歷過程中,字符串test...
只被輸出了一次撩幽,并沒有被輸出三次库继。
說明當代碼執(zhí)行到yield
時,并沒有從函數(shù)test()
中返回窜醉,代碼只是暫停在了yield
處制跟,等下次需要數(shù)據(jù)時,會接著從上次的yield
處接著執(zhí)行酱虎。
生成器比列表節(jié)省內存
如果我們想生成一個從0
到9999
的數(shù)字序列雨膨,用列表的話,是這樣的:
>>> l = [i for i in range(10000)]
>>> sys.getsizeof(l) # 內存占用 87624 字節(jié)
87624
sys
模塊的getsizeof
方法可以查看一個對象的大小读串,單位是字節(jié)
聊记。
用生成器來實現(xiàn)的話撒妈,是這樣的:
>>> l = (i for i in range(10000))
>>> sys.getsizeof(l) # 內存占用 88 字節(jié)
88
可以看到0
到9999
這樣的整數(shù)序列,使用列表的話排监,占用 87624
字節(jié)狰右;使用生成器的話,只占用 88
字節(jié)
5舆床,強制類型轉換
我們已經知道了棋蚌,Python3 中的str
,list
挨队,tuple
谷暮,dict
,set
都是一個類:
>>> type('')
<class 'str'>
>>> type([])
<class 'list'>
>>> type(())
<class 'tuple'>
>>> type({})
<class 'dict'>
>>> type(set())
<class 'set'>
每個類都有構造方法
盛垦,這些構造方法可以將其它類型的數(shù)據(jù)湿弦,轉換
成該類型數(shù)據(jù),我們也可以將這種轉換稱為強制類型轉換
腾夯。
提示:
構造方法
是一個類
的初始化方法颊埃,就是用什么樣的數(shù)據(jù)去構造一個特定類的對象。當介紹到
類與對象
時蝶俱,我們會詳細介紹班利。
str
強制轉換
作用: 將其它類型數(shù)據(jù)轉換成字符串
原型: str(object='') -> str
參數(shù): 任意類型數(shù)據(jù)
返回值: 字符串
示例:
>>> str(1) # 將數(shù)字轉換成字符串
'1'
>>> str([1, 2]) # 將列表轉換成字符串
'[1, 2]'
>>> str((1, 2)) # 將元組轉換成字符串
'(1, 2)'
list
強制轉換
作用: 將一個可迭代類型轉成列表
原型: list(iterable) -> list
參數(shù): 任意可迭代類型數(shù)據(jù)
返回值: 列表
示例:
>>> list((1, 2)) # 將一個元組轉成列表
[1, 2]
>>> list(range(3)) # 將一個 range 對象轉成列表
[0, 1, 2]
tuple
強制轉換
作用: 將一個可迭代類型轉成元組
原型: tuple(iterable) -> tuple
參數(shù): 任意可迭代類型數(shù)據(jù)
返回值: 元組
示例:
>>> tuple([1, 2]) # 將一個列表轉成元組
(1, 2)
>>> tuple(range(3)) # 將一個 range 對象轉成元組
(0, 1, 2)
dict
強制轉換
作用: 將一個可迭代類型數(shù)據(jù)轉成字典
原型: dict(iterable) -> dict
參數(shù):iterable
是一個可迭代對象,并且該對象中的元素是元組
返回值: 字典
示例:
>>> t = ((1, 2), (2, 3)) # t 是一個元組榨呆,其中的元素也是元組
>>> dict(t)
{1: 2, 2: 3}
>>>
>>> l = [(1, 2), (2, 3)] # l 是一個列表罗标,其中的元素是元組
>>> dict(l)
{1: 2, 2: 3}
set
強制轉換
作用: 將一個可迭代類型數(shù)據(jù)轉成集合
原型: set(iterable) -> set
參數(shù): 一個可迭代對象
返回值: 集合
其實,我們在介紹集合
時愕提,都是用的這種方式來聲明的集合馒稍,示例:
>>> set('abc') # 將一個字符串轉成集合
{'b', 'c', 'a'}
>>> set([0, 1]) # 將一個列表轉成集合
{0, 1}
>>> set((0, 1)) # 將一個元組轉成集合
{0, 1}
(完。)
推薦閱讀:
Python 簡明教程 --- 9浅侨,Python 編碼
Python 簡明教程 ---10纽谒,Python 列表
Python 簡明教程 ---11,Python 元組
Python 簡明教程 ---12如输,Python 字典
Python 簡明教程 ---13鼓黔,Python 集合