列表推导式、生成器、迭代器、可迭代介绍--附再谈集合类型

#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'>
>>>

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