微信公衆號:碼農充電站pro
我的主頁:https://codeshellme.github.iohtml
若是你發現特殊狀況太多,那極可能是用錯算法了。
—— Carig Zerounipython
目錄git
前幾節咱們介紹了Python 中四種數據結構的特性和基本用法,本節介紹與數據結構相關的高級特性。github
Python 序列是指,其中存放的元素是有序排列
的,可用下標訪問,字符串
,列表
,元組
都是序列。算法
而字典
與集合
中的元素是無序排列的,所以通常不歸在序列
中。shell
Python 序列有以下特色:微信
不可變
類型下標
訪問,下標可正可負切片
訪問部分連續
元素相加
,相乘
,in 運算
for 循環
遍歷全部元素可使用collections
模塊中的Sequence
類來查看一個對象是不是一個序列:數據結構
>>> isinstance('', collections.Sequence) # 字符串是序列 True >>> isinstance([], collections.Sequence) # 列表是序列 True >>> isinstance((), collections.Sequence) # 元組是序列 True >>> isinstance({}, collections.Sequence) # 字典不是序列 False >>> isinstance(set(), collections.Sequence) # 集合不是序列 False
提示:app
1,
isinstance
函數用於查看一個對象屬於某個類函數2,在使用
模塊
時,要先import
該模塊
可迭代類型
咱們知道str
,list
,tuple
,dict
,set
均可用for 循環
來遍歷,這個遍歷的過程就是一個迭代
過程,這些類型都是可迭代
類型。
可迭代的類型,都實現了__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
迭代器
迭代器
是一種可迭代
的對象。
迭代器必定是可迭代的,可迭代的對象不必定是迭代器。
迭代器要實現兩個魔法方法:__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
迭代器有一些通用函數,下面咱們介紹一些經常使用的。
1.enumerate
函數
在Python3 中,enumerate
其實是一個類
,可經過help(enumerate)
查看,也能夠把它當作函數來使用。
其常常被用在for 循環
中,便可遍歷下標,又能遍歷數據。
做用: 用於給一個
可迭代
的對象,添加下標
原型: enumerate(iterable[, start]) -> iterator
參數 iterable: 一個可迭代的對象
參數 start: 下標起始位置
返回值: 一個enumerate
對象,同時也是一個迭代器
示例:
>>> l = enumerate(['a', 'c', 'b']) # 參數是一個列表 >>> type(l) <class 'enumerate'> >>> isinstance(l, collections.Iterator) # 是一個迭代器 True >>> for index, item in l: # for 循環遍歷,能遍歷出下標 ... print(index, item) ... 0 a 1 c 2 b
2.iter
函數
做用:將一個可迭代的序列
iterable
轉換成迭代器
原型:iter(iterable) -> iterator
參數:iterable 是一個可迭代的序列
返回值:一個迭代器
示例:
>>> iter('123') # 參數是字符串 <str_iterator object at 0x7fcb7dd320b8> # str 迭代器 >>> iter([1, 2, 3]) # 參數是列表 <list_iterator object at 0x7fcb7dd4a0b8> # list 迭代器 >>> iter((1, 2, 3)) # 參數是元組 <tuple_iterator object at 0x7fcb7dd4a0b8> # tuple 迭代器 >>> iter(set([1, 2, 3])) # 參數是集合 <set_iterator object at 0x7fcb7d2c5e10> # set 迭代器 >>> iter({'a':1, 'b':2}) # 參數是字典 <dict_keyiterator object at 0x7fcb7f467098> # dict 迭代器
3.next
函數
做用:返回迭代器的下一個元素
原型:next(iterator[, default]) -> item
參數 iterator:是一個迭代器類型
參數 default:任意類型數據,可省
返回值:當
迭代器中有元素
時:返回迭代器中的下一個元素
當迭代器中沒有元素
且沒有default 參數
時:拋出StopIteration
異常
當迭代器中沒有元素
且有default 參數
時:返回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 中沒有元素,返回第二個參數 7 7
4.len
函數
做用:用於計算一個對象
obj
中的元素的個數
原型:len(obj, /)
參數:通常obj
是一個可迭代類型對象,實際上,只要實現了__len__
方法的對象,均可以使用該函數
返回值:一個整數
示例:
>>> len('abc') 3 >>> len([1, 2, 3]) 3
5.max
函數
做用:返回可迭代對象
iterable
中的最大元素
原型:max(iterable)
參數:iterable
是一個可迭代的對象,而且iterable
中的元素可比較
返回值:最大值
示例:
>>> max([1, 2]) 2 >>> max([1, 2, 3]) 3 >>> max('b', 'a') 'b' >>> max('abc') 'c' >>> max(1, 'a') # 整數與字符串不是同類型,不可比較 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: '>' not supported between instances of 'str' and 'int'
6.min
函數
做用:返回可迭代對象
iterable
中的最小元素
原型:min(iterable)
參數:iterable
是一個可迭代的對象,而且iterable
中的元素可比較
返回值:最小值
示例:
>>> min([1, 2]) 1 >>> min([2, 3]) 2 >>> min('abc') 'a' >>> min('b', 'c') 'b' >>> min('b', 2) # 整數與字符串不是同類型,不可比較 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: '<' not supported between instances of 'int' and 'str'
7.sum
函數
做用:計算可迭代對象
iterable
中的數據之和,最後在加上start
原型:sum(iterable, start=0, /)
參數:iterable
是一個可迭代對象,其中的元素是數字類型
返回值:全部元素之和
示例:
>>> sum([1, 2, 3]) # 計算 1,2,3 之和 6 >>> sum([1, 2, 3], 5) # 計算 1,2,3 之和,再加上 5 11
8.reversed
函數
reversed
其實是一個類,可用help(reversed)
查看。
做用:將一個序列
sequence
反轉
原型:reversed(sequence)
參數: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]
列表生成式
,又叫列表推導式
,用於從一個可迭代對象
生成一個列表
,它是一種代碼簡寫形式,其優勢是代碼簡潔優雅。
好比,咱們有一個列表 [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
有關,也可無關可迭代對象
列表生成式中的if
判斷
列表生成式中也能夠有if
判斷,當判斷條件
成立時,纔會執行表達式,並將該表達式的結果append
到新的列表中。
這裏的if
判斷沒有else
部分,判斷條件
通常與item
有關。
以下:
示例:
l = [1, 3, 5] # 只有當 l 中的元素大於 1 時,纔算平方 l2 = [i * i for i in l if i > 1] print(l2)
range
函數
在Python2.x 中
,range
是一個函數
。
在Python3.x
中,range
是一個類
,可用help(range)
查看其手冊。
>>> range <class 'range'>
下面介紹Python3.x
中range
的用法,有兩種參數形式:
做用:生成一個從
start
到stop
的,步長爲step
的,可迭代的整數序列,該序列包含start
,不包含stop
,即遵循左開右閉
原則
原型:range(stop) -> range object
range(start, stop[, step]) -> range object參數:
當只有
stop
參數時,該序列從0
開始到stop
,步長爲1
當有start
和stop
參數時,該序列從start
開始到stop
,步長爲1
當有step
參數時,步長爲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]
生成器也是一個迭代器
。生成器跟列表有點像,但優勢是比列表節省內存
。
對於列表,Python 會爲列表中的每一個元素都分配實實在在的內存空間,若是列表中的元素不少,那麼列表將消耗大量內存。
而對於生成器,Python 並不會爲其中的每一個元素都分配內存。
生成器記錄的是一種算法,是如何生成數據的算法,在每次用到數據時,纔會去生成數據,而不會一開始就將全部的數據準備好。
所以,對於相同的功能,生成器
和列表
都能完成,而生成器能夠節省大量的內存。
建立生成器有兩種方式:
列表生成式
中的中括號[]
改成小括號()
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'>
注意,咱們定義了一個函數,這裏咱們只是爲了演示如何使用yield
來建立生成器,而不用過多關注如何定義函數。
函數
的概念咱們會在後續章節詳細介紹。
執行以上代碼,輸出以下:
<generator object test at 0x7fde1cdaa3b8> <class'generator'>
你會發現,字符串test...
並無被打印出來。
你可能會有疑問,既然代碼t = test()
已經執行了,那整個test()
函數中的代碼都應該執行完了纔對,那字符串test...
怎麼會沒有打印呢?
那是由於,生成器
中代碼的執行是惰性
的。當執行t = test()
這行代碼時,test()
函數並無被執行。
前邊咱們說過,生成器記錄的是一個算法
,而不是真正的數據,數據只有當使用到的時候,纔會去生成。
因此,變量 t
中只是一個算法,而沒有數據。
由於,生成器也是一個迭代器,因此生成器可使用next()
函數來訪問其中的數據:
i = next(t) print('i value is', i)
執行上面這行代碼後,程序會輸出:
test... yield tmp:1 i value is 1
字符串test...
被打印,說明test()
執行了。
當代碼執行到yield
時,變量i
會接收到yield
返回的數據,此時,代碼會從yield
處跳出test()
函數。
若是接下來,再也不遍歷變量t
中的數據,那麼整個代碼就執行結束了。
若是咱們再次執行代碼:
j = next(t) print('j value is', j)
程序會輸出:
yield tmp:9 j value is 9
可見代碼會在上次yield
的地方,再次向下執行。
咱們再次執行代碼:
k = next(t) print('k value is', k)
程序會輸出:
yield tmp:25 k value is 25
當t
中的元素被遍歷完後,若是再次執行next(t)
,則會拋出StopIteration
異常。
使用next()
函數來遍歷生成器中的全部元素是很麻煩的,咱們能夠像遍歷列表同樣,用for 循環
來遍歷生成器中的元素:
for i in t: print(i)
輸出以下:
test... yield tmp:1 1 yield tmp:9 9 yield tmp:25 25
整個遍歷過程當中,字符串test...
只被輸出了一次,並無被輸出三次。
說明當代碼執行到yield
時,並無從函數test()
中返回,代碼只是暫停在了yield
處,等下次須要數據時,會接着從上次的yield
處接着執行。
生成器比列表節省內存
若是咱們想生成一個從0
到9999
的數字序列,用列表的話,是這樣的:
>>> l = [i for i in range(10000)] >>> sys.getsizeof(l) # 內存佔用 87624 字節 87624
sys
模塊的getsizeof
方法能夠查看一個對象的大小,單位是字節
。
用生成器來實現的話,是這樣的:
>>> l = (i for i in range(10000)) >>> sys.getsizeof(l) # 內存佔用 88 字節 88
能夠看到0
到9999
這樣的整數序列,使用列表的話,佔用 87624
字節;使用生成器的話,只佔用 88
字節
咱們已經知道了,Python3 中的str
,list
,tuple
,dict
,set
都是一個類:
>>> type('') <class 'str'> >>> type([]) <class 'list'> >>> type(()) <class 'tuple'> >>> type({}) <class 'dict'> >>> type(set()) <class 'set'>
每一個類都有構造方法
,這些構造方法能夠將其它類型的數據,轉換
成該類型數據,咱們也能夠將這種轉換稱爲強制類型轉換
。
提示:
構造方法
是一個類
的初始化方法,就是用什麼樣的數據去構造一個特定類的對象。當介紹到
類與對象
時,咱們會詳細介紹。
str
強制轉換
做用: 將其它類型數據轉換成字符串
原型: str(object='') -> str
參數: 任意類型數據
返回值: 字符串
示例:
>>> str(1) # 將數字轉換成字符串 '1' >>> str([1, 2]) # 將列表轉換成字符串 '[1, 2]' >>> str((1, 2)) # 將元組轉換成字符串 '(1, 2)'
list
強制轉換
做用: 將一個可迭代類型轉成列表
原型: list(iterable) -> list
參數: 任意可迭代類型數據
返回值: 列表
示例:
>>> list((1, 2)) # 將一個元組轉成列表 [1, 2] >>> list(range(3)) # 將一個 range 對象轉成列表 [0, 1, 2]
tuple
強制轉換
做用: 將一個可迭代類型轉成元組
原型: tuple(iterable) -> tuple
參數: 任意可迭代類型數據
返回值: 元組
示例:
>>> tuple([1, 2]) # 將一個列表轉成元組 (1, 2) >>> tuple(range(3)) # 將一個 range 對象轉成元組 (0, 1, 2)
dict
強制轉換
做用: 將一個可迭代類型數據轉成字典
原型: dict(iterable) -> dict
參數: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
強制轉換
做用: 將一個可迭代類型數據轉成集合
原型: set(iterable) -> set
參數: 一個可迭代對象
返回值: 集合
其實,咱們在介紹集合
時,都是用的這種方式來聲明的集合,示例:
>>> set('abc') # 將一個字符串轉成集合 {'b', 'c', 'a'} >>> set([0, 1]) # 將一個列表轉成集合 {0, 1} >>> set((0, 1)) # 將一個元組轉成集合 {0, 1}
(完。)
推薦閱讀:
歡迎關注做者公衆號,獲取更多技術乾貨。