列表推導式、生成器、迭代器、可迭代介紹--附再談集合類型

#list

#元素訪問

li = []
print(li[0])
print(li[-1])
print(li[-2])

查找元素位置

li.index(element)
如果element不在li中會拋出異常,因此不確定一定要用try-except捕捉

添加元素

li.append(element)
li.append(element)

#合併list

list1.extend(list2)

注意append作爲一個元素,extend則是直接合並拼接。

# 示例 append() extend()的區別
>>> l1 = [1,2,3,'hello']
>>> l2 = ['world',5,6,7]
>>> l1.append(l2)                                                                                           
>>> l1
[1, 2, 3, 'hello', ['world', 5, 6, 7]]
>>>
>>> l1 = [1,2,3,'hello']
>>> l1.extend(l2)
>>> l1
[1, 2, 3, 'hello', 'world', 5, 6, 7]
>>>

Empty 和 None 不是一回事

l3 = []

>>> if not l3:
...     print('Empty')
... 
Empty
>>> if l3 is None:
...     print('None')
... 
>>>
>>> [] == None
False
>>>
空和None不是一回事,空只是沒有元素,但在內存中還是要爲這對象容器分配一些信息。
而None則表示什麼都沒有。
so 在Python中判斷容器爲空,一般用法:if not object:if len(object)==0

list迭代

for i in list1: # 迭代器
    pass

for i in range(len(list1)):  #索引
    list1[i]
    for j in range(i+1, len(list1)):
        pass
range(n) 就是 range(0,n) 就是 [0, n-1]
一般除非必須獲取索引的場景,否則不使用索引方式,因爲可以通過特定元素獲取索引,list.index() 或通過enum()方法

函數返回值 tuple() or list[] 
return a, b 就相當於返回元組tuple(a, b), 因此是不可更改的
也可以明確返回list[],return [a, b]

tuple 元組

相當於是 const list,使用 ( ) 表示

dict 字典 , dict無序, value可以是各種複合數據類型list,tuple,dict都行

d = {}
d = {'a':1, 'b':2, 1:'one', 2:'two'}
d = dict(key = value, key = value...)

通過key訪問value

>>> d = { 'b':2, 'a':1, 2:'two' , 1:'one', 'comp':[1,2,'hello'] }
>>> d[1]                                                                                                    
'one'
>>> d['a']
1   
>>> d['comp']
[1, 2, 'hello']
>>>
# 判斷元素是否存在, 依賴 key, 對於dict看不到value任何信息,唯一知道的就是key
>>> 'b' in d
True
>>> 'c' in d
False
>>> 'two' in d
False
>>>
>>> len(d)
5
# 添加元素
d[newKey] = value
# 遍歷
>>> for key in d:
...     print(d[key])
... 
2
1
two
one
[1, 2, 'hello']
>>> 
>>> for key,value in d.items():
...     print(key, value)
... 
b 2
a 1
2 two
1 one
comp [1, 2, 'hello']
>>>
>>> for k in d.keys():
...     print(d[k])
... 
2
1
two
one
[1, 2, 'hello']
>>>
>>> for k in d.keys():
...     print(k, d[k])
... 
b 2
a 1
2 two
1 one
comp [1, 2, 'hello']

set集合, 元素無重複

s_a = set([1,2,3,4,5,4,5,6,7,7])
s_b = set([4,5,4,5,6,7,7])

>>> s_a
{1, 2, 3, 4, 5, 6, 7}
>>> len(s_a)
7
>>> s_b = set([4,5,4,5,6,7,7])
# >>> s_b = {4,5,4,5,6,7,7}  或者像dict使用{ }
# 聲明空 set
s3 = set()

>>> s_b
{4, 5, 6, 7}
# 判斷元素是否存在
(element in set)

# 交集、 並集  或用方法 set.intersection()  set.union()
>>> s3 = set()
>>> len(s3)
0
>>> s4 = s_a | s3    # s_a.untion(s3)
>>> s4
{1, 2, 3, 4, 5, 6, 7}
>>>
>>> s5 = s_a & s3   # s_a.intersection(s3)
>>> s5
set()
>>> len(s5)
0
>>> s_a & s_b
{4, 5, 6, 7}
>>>
# 差集
(s_a - s_b)   # s_a.difference(s_b)

# 差集 A - (A & B)
print(s_a - s_b)
print(s_a.difference(s_b))

# 對稱差 (A | B) - (A & B)
print(s_a ^ s_b)
print(s_a.symmetric_difference(s_b))

序列類型切片slice [start: end: steps] 表示範圍左閉右開[start, end) 且steps缺省 = 1

>>> l1 = list(range(10))
>>> l1
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> l1[5:7]
[5, 6]
>>>
# end超過實際大小(越界),會按照實際大小計算
# 負值
# end邊界, 最後一個元素對應-1, 倒數第二個對應-2 ; 因此可以利用切片特性,進行逆序遍歷,快速翻轉reverse
list[::-1]
>>> l1[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>>
# 切片是生成一個新的對象,原list不變

列表推導式

case1 使用列表推導式完成同樣功能:生成0-20的偶數
'''
li = []
for i in range(20):
    if(i%2)==0:
        li.append(i)
print(li)
'''
>>> li = [i*2 for i in range(10)]
>>> l1
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> l2 = [i%2==0 for i in range(20)]
>>> l2
# 問題? 如何在列表推導式中用if過濾條件? 答案如下
>>> l2 = [i for i in range(20) if i%2==0]
>>> l2
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>>
# 列表推導式生成dict
>>> dict2 = {x:x%2==0 for x in range(20)}
>>> dict2
{0: True, 1: False, 2: True, 3: False, 4: True, 5: False, 6: True, 7: False, 8: True, 9: False, 10: True, 11: False, 12: True, 13: False, 14: True, 15: False, 16: True, 17: False, 18: True, 19: False}
>>>

二維數組

li_2d = [[0] * 3] * 3
>>> li_2d
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> li_2d[0][0] = 100
>>> li_2d
[[100, 0, 0], [100, 0, 0], [100, 0, 0]]
>>>

# 思考: 爲什麼修改[0][0]卻改變了3個元素? 因爲使用的引用,三行實際是隻有一份,引用了3次,淺拷貝

li_2d = [ [0] * 3 for i in range(3)]  # 這樣纔是深拷貝
>>> li_2d
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> li_2d[0][0] = 200
>>> li_2d
[[200, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> len(li_2d)
3
>>>

生成器

問題的提出

  • 場景:創建一個巨大的列表而僅僅需要訪問其中少量幾個元素
  • 如果列表元素可以按照某種算法推算出來,那我們是否可以在循環的過程中不斷推算出後續的元素呢?
    這樣就不必創建完整的list,從而節省大量的空間
    實際使用時纔去生成,把真正的計算推遲到你使用的時候,生成器就是爲了解決惰性計算問題

# case1 平方表
square_table = []
for i in range(10000):
    square_table.append(i*i)

square_generator = (x*x for x in range(50000))
for i in range(10):
    print(next(square_generator))

>>> type(square_generator)
<class 'generator'>
>>>
>>> output
0
1
4
9
16
25
36
49
64
81    
>>> print(next(square_generator))
100
>>> print(next(square_generator))
121
>>> print(next(square_generator))
144
>>>
>>> range(10)
range(0, 10)
在python3中range()函數就是這樣的

# case2 以菲波那切數列爲例
def fib(limit):
    n, a, b = 0, 0, 1
    while n < limit:
        yield b
        a, b = b, a + b
        n += 1
    return 'done'

f=fib(5)
type(f)
print(next(f))

<class 'generator'>
>>> print(next(f))
1
>>> print(next(f))
1
>>> print(next(f))
2
>>> print(next(f))
3
>>> pr

生成器、迭代器、可迭代的概念

可以直接作用於for循環的對象,統稱爲可迭代對象:Iterable
可以被next()調用並不斷返回下一個值得對象成爲迭代器:Iterator(強調特性:惰性計算序列, 因此generator一定是Iterator)

Iterable屬性的對象一定是Iterator,即Iterator ->(充分不必要)-> Iterable

from collections import Iterable
from collections import Iterator

>>>
>>> isinstance([1,2,3], Iterable)
True
>>> isinstance([1,2,3], Iterator)
False
>>> isinstance({}, Iterable)
True
>>> isinstance({}, Iterator)
False
>>> isinstance('abcd', Iterable)
True
>>> isinstance('abcd', Iterator)
False
>>> isinstance(1234, Iterable)
False
>>> isinstance(1234, Iterator)
False
>>> g = (x*x for x in range(10))
>>> type(g)
<class 'generator'>
>>> isinstance(g, Iterable)
True
>>> isinstance(g, Iterator)
True
>>>
# 因此這裏g是生成器屬於惰性計算序列,因此是Iterator。Iterable && Iterator,可以用for或next迭代
>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
>>> next(g)
9
>>> next(g)
16
>>> next(g)
25
>>>

# 集合數據類型list、dict、str是Iterable但不是Iterator,不過可以通過iter()函數獲得一個Iterator對象
>>> isinstance('abcd', Iterator)
False
>>> isinstance(iter('abcd'), Iterator)
True
>>> res = iter('asdfds')
>>> res
<str_iterator object at 0x7f199963bcf8>
>>> type(res)
<class 'str_iterator'>
>>>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章