Python3數據類型

類型

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錯誤,返回值包含在StopIterationvalue中:

>>> 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對象,但listdictstr雖然是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以下版本中會得到語法錯誤異常。

本文參考
https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143167793538255adf33371774853a0ef943280573f4d000

發佈了53 篇原創文章 · 獲贊 3 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章