類型
1. 整數
2. 浮點數
3. 字符串
3.1 字符串的格式化
使用 %
和佔位符
%d —- 整數
%f —- 浮點數
%s —- 字符串
%x —- 十六進制整數
比如:
>>> "name:%s , gender: %s, age: %s" % ("張三","man",20)
'name:張三 , gender: man, age: 20'
其中,格式化整數和浮點數還可以指定是否補0和整數與小數的位數:
字符串裏面的%是一個普通字符怎麼辦?這個時候就需要轉義,用%%來表示一個%:
4. 布爾值
5. list
5.1 有序集合 – [a,b]
- 有序(打印順序同插入順序)
- 可通過索引訪問
- 可添加,插入,刪除,替換
5.2 多維數組
list元素也可以是另一個list
因此s可以看成是一個二維數組,類似的還有三維、四維……數組,不過很少用到。
6. tuple
6.1 元組 – (a,b)
- 有序(打印順序同插入順序)
- 一旦初始化就不能修改
- 可以通過索引訪問
6.2 tuple只有一個元素時
Python在顯示只有1個元素的tuple時,也會加一個逗號 ,
,以免你誤解成數學計算意義上的括號。
這是因爲括號()既可以表示tuple,又可以表示數學公式中的小括號,這就產生了歧義,因此,Python規定,這種情況下,按小括號進行計算,計算結果自然是1。
6.3 “可變的”tuple
表面上看,tuple的元素確實變了,但其實變的不是tuple的元素,而是list的元素。tuple一開始指向的list並沒有改成別的list,所以,tuple所謂的“不變”是說,tuple的每個元素,指向永遠不變。即指向’a’,就不能改成指向’b’,指向一個list,就不能改成指向其他對象,但指向的這個list本身是可變的!
理解了“指向不變”後,要創建一個內容也不變的tuple怎麼做?那就必須保證tuple的每一個元素本身也不能變。
6.4 tuple 和 list
不可變的tuple有什麼意義?因爲tuple不可變,所以代碼更安全。如果可能,能用tuple代替list就儘量用tuple。
7. dict
7.1 字典 - {“a” : 9, “b” : 10}
dict的支持,dict全稱dictionary,在其他語言中也稱爲map,使用鍵-值(key-value)存儲,具有極快的查找速度。
- 無序
- 不可通過索引訪問
7.2 查詢
由於一個key只能對應一個value,所以,多次對一個key放入value,後面的值會把前面的值沖掉:
要避免key不存在的錯誤,有兩種辦法,
- 一是通過in判斷key是否存在:
- 二是通過dict提供的get方法,如果key不存在,可以返回None,或者自己指定的value:
7.3 dict 和list
- list中,1000個元素查找速度比10個元素要慢很多
- dict中,1000個元素查找速度和10個元素差不多
爲什麼dict查找速度這麼快?因爲dict的實現原理和查字典是一樣的。假設字典包含了1萬個漢字,我們要查某一個字,一個辦法是把字典從第一頁往後翻,直到找到我們想要的字爲止,這種方法就是在list中查找元素的方法,list越大,查找越慢。
第二種方法是先在字典的索引表裏(比如部首表)查這個字對應的頁碼,然後直接翻到該頁,找到這個字。無論找哪個字,這種查找速度都非常快,不會隨着字典大小的增加而變慢。
和list比較,dict有以下幾個特點:
- 查找和插入的速度極快,不會隨着key的增加而變慢;
- 需要佔用大量的內存,內存浪費多。
而list相反:
- 查找和插入的時間隨着元素的增加而增加;
- 佔用空間小,浪費內存很少。
所以,dict是用空間來換取時間的一種方法。
dict可以用在需要高速查找的很多地方,在Python代碼中幾乎無處不在,正確使用dict非常重要,需要牢記的第一條就是dict的key必須是不可變對象。
這是因爲dict根據key來計算value的存儲位置,如果每次計算相同的key得出的結果不同,那dict內部就完全混亂了。這個通過key計算位置的算法稱爲哈希算法(Hash)。
要保證hash的正確性,作爲key的對象就不能變。在Python中,字符串、整數等都是不可變的,因此,可以放心地作爲key。而list是可變的,就不能作爲key:
8. set
8.1 沒有存儲value – set( [“a”, “b”] )
- 無序
- 無重複
- 不可通過索引訪問
set可以看成數學意義上的無序和無重複元素的集合,因此,兩個set可以做數學意義上的交集、並集等操作:
8.2 set和dict
set和dict的唯一區別僅在於沒有存儲對應的value,但是,set的原理和dict一樣,所以,同樣不可以放入可變對象,因爲無法判斷兩個可變對象是否相等,也就無法保證set內部“不會有重複元素”。試試把list放入set,看看是否會報錯。
類型判斷
- isinstance(object, classinfo)
- issubclass(class, classinfo)
類型轉化
類型操作
1. 迭代
1.1 dict
迭代key
>>> for value in d:
... print k
迭代value
>>> for value in d.values():
... print k
迭代key,value
>>> for k,v in d.items():
... print k ,v
1.2 字符串
>>> for ch in "hello":
... print ch
1.3 如何判斷一個對象是否可迭代
當我們使用for循環時,只要作用於一個可迭代對象,for循環就可以正常運行,而我們不太關心該對象究竟是list還是其他數據類型。
那麼,如何判斷一個對象是可迭代對象呢?方法是通過collections模塊的Iterable類型判斷:
>>> from collections import Iterable
>>> isinstance('abc', Iterable) # str是否可迭代
True
>>> isinstance([1,2,3], Iterable) # list是否可迭代
True
>>> isinstance(123, Iterable) # 整數是否可迭代
False
1.4 for循環中訪問多個變量
>>> for x,y,z in [(2,3,4),(5,6,7)]:
... print x,y,z
...
2 3 4
5 6 7
>>> for x,y in [(2,3,4),(5,6,7)]:
... print x,y
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack
>>> for x,y,z in [(2,3,4),(5,6,7)]:
... print x,y
...
2 3
5 6
>>>
1.5 for循環中訪問下標
對於有序列表
>>> for i, value in enumerate(['A', 'B', 'C']):
... print(i, value)
...
0 A
1 B
2 C
2. 列表生成式
列表生成式即List Comprehensions,是Python內置的非常簡單卻強大的可以用來創建list的生成式。
- 簡單的
>>> list(range(1, 11))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
- 遍歷型的
>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
- 條件型的
>>> [x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]
- 多層循環
>>> [m + n for m in 'ABC' for n in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
- 多個變量:
>>> d = {'x': 'A', 'y': 'B', 'z': 'C' }
>>> [k + '=' + v for k, v in d.items()]
['y=B', 'x=A', 'z=C']
3. 生成器
- 保存的是算法,而不是數據
- 一邊循環一邊計算
3.1 列表生成器
通過列表生成式,我們可以直接創建一個列表。但是,受到內存限制,列表容量肯定是有限的。而且,創建一個包含100萬個元素的列表,不僅佔用很大的存儲空間,如果我們僅僅需要訪問前面幾個元素,那後面絕大多數元素佔用的空間都白白浪費了。
只要把一個列表生成式的[]改成(),就創建了一個generator:
>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>
兩種方式打印生成器
- next方法 – 很少用
>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
- 遍歷生成器
>>> g = (x * x for x in range(10))
>>> for n in g:
... print(n)
...
0
1
4
9
16
...
3.2 函數生成器
斐波拉契數列用列表生成式寫不出來,但是,用函數把它打印出來卻很容易:
def fib(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
a, b = b, a + b
n = n + 1
return 'done'
注意,賦值語句:
a, b = b, a + b
相當於:
t = (b, a + b) # t是一個tuple
a = t[0]
b = t[1]
如果把它改成生成器,只需要把print(b)改爲yield b就可以了:
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'
如果一個函數定義中包含yield關鍵字,那麼這個函數就不再是一個普通函數,而是一個generator:
>>> f = fib(6)
>>> f
<generator object fib at 0x104feaaa0>
最難理解的就是generator和函數的執行流程不一樣。函數是順序執行,遇到return
語句或者最後一行函數語句就返回。而變成generator的函數,在每次調用next()
的時候執行,遇到yield
語句返回,再次執行時從上次返回的yield
語句處繼續執行。
>>> for n in fib(6):
... print(n)
...
1
1
2
3
舉個簡單的例子,定義一個generator,依次返回數字1,3,5:
def odd():
print('step 1')
yield 1
print('step 2')
yield(3)
print('step 3')
yield(5)
調用該generator時,首先要生成一個generator對象,然後用next()函數不斷獲得下一個返回值:
>>> o = odd()
>>> next(o)
step 1
1
>>> next(o)
step 2
3
>>> next(o)
step 3
5
>>> next(o)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
但是用for
循環調用generator時,發現拿不到generator的return
語句的返回值。如果想要拿到返回值,必須捕獲StopIteration
錯誤,返回值包含在StopIteration
的value
中:
>>> g = fib(6)
>>> while True:
... try:
... x = next(g)
... print('g:', x)
... except StopIteration as e:
... print('Generator return value:', e.value)
... break
...
g: 1
g: 1
g: 2
g: 3
g: 5
g: 8
Generator return value: done
生成器不但可以作用於for循環,還可以被next()函數不斷調用並返回下一個值,直到最後拋出StopIteration錯誤表示無法繼續返回下一個值了。
楊輝三角
def yangfei(max):
L = [1]
n = 0
while n < max:
if n == 0:
L =[1]
elif n ==1:
L =[1,1]
else:
L = [ m+n for i,m in enumerate(L[:-1]) for j,n in enumerate(L[1:]) if i==j]
L.insert(0,1)
L.append(1)
n = n+1
yield L
def triangles(max):
L = [1]
n = 0
while n < max:
yield L
L.append(0)
# (使L最後一個元素可用列表生成式賦值爲1)
L = [L[i - 1] + L[i] for i in range(len(L))]
n = n+1
return
for t in yangfei(10):
print (t)
for t in triangles(10):
print(t)
4. 迭代器
4.1 Iterable
我們已經知道,可以直接作用於for循環的數據類型有以下幾種:
一類是集合數據類型,如list、tuple、dict、set、str等;
一類是generator,包括生成器和帶yield的generator function。
這些可以直接作用於for循環的對象統稱爲可迭代對象:Iterable。
可以使用isinstance()判斷一個對象是否是Iterable對象:
>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False
而生成器不但可以作用於for
循環,還可以被next()
函數不斷調用並返回下一個值,直到最後拋出StopIteration
錯誤表示無法繼續返回下一個值了。
4.2 Iterator
可以被next()函數調用並不斷返回下一個值的對象稱爲迭代器:Iterator。
可以使用isinstance()
判斷一個對象是否是Iterator
對象:
>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False
生成器都是Iterator
對象,但list
、dict
、str
雖然是Iterable
,卻不是Iterator
。
把list、dict、str等Iterable變成Iterator可以使用iter()函數:
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True
你可能會問,爲什麼list、dict、str等數據類型不是Iterator?
這是因爲Python的Iterator對象表示的是一個數據流,Iterator對象可以被next()函數調用並不斷返回下一個數據,直到沒有數據時拋出StopIteration錯誤。可以把這個數據流看做是一個有序序列,但我們卻不能提前知道序列的長度,只能不斷通過next()函數實現按需計算下一個數據,所以Iterator的計算是惰性的,只有在需要返回下一個數據時它纔會計算。
Iterator甚至可以表示一個無限大的數據流,例如全體自然數。而使用list是永遠不可能存儲全體自然數的。
from collections import Iterable
from collections import Iterator
print ( isinstance((x for x in range(10)), Iterable))
print ( isinstance((x for x in range(10)), Iterator))
print ( isinstance([x for x in range(10)], Iterable))
print ( isinstance([x for x in range(10)], Iterator))
# True
# True
# True
# False
參考:http://blog.csdn.net/zengchen73/article/details/76067246
4.3 小結
凡是可作用於for
循環的對象都是Iterable
類型;
凡是可作用於next()
函數的對象都是Iterator
類型,它們表示一個惰性計算的序列;
集合數據類型如list、dict、str等是Iterable但不是Iterator,不過可以通過iter()函數獲得一個Iterator對象。
Python的for循環本質上就是通過不斷調用next()函數實現的,例如:
for x in [1, 2, 3, 4, 5]:
pass
實際上完全等價於:
# 首先獲得Iterator對象:
it = iter([1, 2, 3, 4, 5])
# 循環:
while True:
try:
# 獲得下一個值:
x = next(it)
except StopIteration:
# 遇到StopIteration就退出循環
break
5. 注意事項
5.1 生成器不能有返回值
既然生成器函數也是函數,那麼它可以使用return輸出返回值嗎?
不行的親,是這樣的,生成器函數已經有默認的返回值——生成器了,你不能再另外給一個返回值;對,即使是return None也不行。但是它可以使用空的return語句結束。如果你堅持要爲它指定返回值,那麼Python將在定義的位置贈送一個語法錯誤異常,就像這樣:
>>> def i_wanna_return():
... yield None
... return None
...
File "<stdin>", line 3
SyntaxError: 'return' with argument inside generator
5.2 在帶有finally子句的try塊中yield
好吧,那人家需要確保釋放資源,需要在try…finally中yield,這會是神馬情況?(我就是想玩你)我在finally中還yield了一次!
Python會在真正離開try…finally時再執行finally中的代碼,而這裏遺憾地告訴你,暫停不算哦!所以結局你也能猜到吧!
>>> def play_u():
... try:
... yield 1
... yield 2
... yield 3
... finally:
... yield 0
...
>>> for val in play_u(): print val,
...
1 2 3 0
*這與return的情況不同。return是真正的離開代碼塊,所以會在return時立刻執行finally子句。
*另外,“在帶有finally子句的try塊中yield”定義在PEP 342中,這意味着只有Python 2.5以上版本才支持這個語法,在Python 2.4以下版本中會得到語法錯誤異常。