1.列表,字符串切片
注意 [a : b ] 包头不包尾
倒数第一个元素的索引值是-1
字符串'abc'
也可以看成是一种list,每个元素就是一个字符。因此,字符串也可以用切片操作,结果仍是字符串:
例子
>>> L = list(range(100)) >>> L [0, 1, 2, 3, ..., 99] #前11-20个数 >>> L[10:20] [10, 11, 12, 13, 14, 15, 16, 17, 18, 19] #前10个数,每两个取一个: >>> L[:10:2] [0, 2, 4, 6, 8]
#字符串切片>>> 'ABCDEFG'[::2]
'ACEG'
Python没有针对字符串的截取函数,只需要切片一个操作就可以完成。Python的切片非常灵活,一行代码就可以实现很多行循环才能完成的操作。有了切片操作,很多地方循环就不再需要了,例如借助负数索引。
2.迭代
如果给定一个list或tuple,我们可以通过for
循环来遍历这个list或tuple,这种遍历我们称为迭代(Iteration)
Python的for
循环抽象程度要高于C的for
循环,因为Python的for
循环不仅可以用在list或tuple上,还可以作用在其他可迭代对象上。
list这种数据类型虽然有下标,但很多其他数据类型是没有下标的,但是,只要是可迭代对象,无论有无下标,都可以迭代,比如dict就可以迭代:
>>> d = {'a': 1, 'b': 2, 'c': 3} >>> for key in d: ... print(key) ... a c b
因为dict的存储不是按照list的方式顺序排列,所以,迭代出的结果顺序很可能不一样。
默认情况下,dict迭代的是key。如果要迭代value,可以用for value in d.values()
,如果要同时迭代key和value,可以用for k, v in d.items()
。
字符串也是可迭代对象,因此也可以作用于for
循环:
所以,当我们使用for
循环时,只要作用于一个可迭代对象,for
循环就可以正常运行,而我们不太关心该对象究竟是list还是其他数据类型。
那么,如何判断一个对象是可迭代对象呢?方法是通过collections模块的Iterable类型判断:-----------------判断对象是否是iterable类的实例!isinstance
>>> #from collections import Iterable
>>> from collections.abc import Iterable #弃用警告:从collections中导入ABCs已被弃用,并在python3.8中将停止工作,可使用collections.abc代替它进行使用>>> isinstance('abc', Iterable) # str是否可迭代 True >>> isinstance([1,2,3], Iterable) # list是否可迭代 True >>> isinstance(123, Iterable) # 整数是否可迭代 False
如果要对list实现类似Java那样的下标循环怎么办?Python内置的enumerate
函数可以把一个list变成索引-元素对,这样就可以在for
循环中同时迭代索引和元素本身:
>>> for i, value in enumerate(['A', 'B', 'C']): ... print(i, value) ... 0 A 1 B 2 C
上面的for
循环里,同时引用了两个变量,在Python里是很常见的~~~~~
3.列表生成式 List Comprehensions
是Python内置的非常简单却强大的可以用来创建list的生成式
range()函数
列表推导式是通过一个可迭代对象来生成列表的,range()可以说是列表推导式中最常用的可迭代对象了 ;对列表推导式来说,range()是其中的精髓之一
注意 range(a , b) 包头不包尾
列表推导式
复杂点的列表推导式:
# in后面跟其他可迭代对象,如字符串 list_c = [7 * c for c in "python"] print(list_c) # 带if条件语句的列表推导式 list_d = [d for d in range(6) if d % 2 != 0] print(list_d) # 多个for循环 list_e = [(e, f * f) for e in range(3) for f in range(5, 15, 5)] print(list_e) # 嵌套列表推导式,多个并列条件 ------>>可以进行嵌套的列表推导,与嵌套for循环的原理相同. list_g = [[x for x in range(g - 3, g)] for g in range(22) if g % 3 == 0 and g != 0] print(list_g)
#运行结果
['ppppppp', 'yyyyyyy', 'ttttttt', 'hhhhhhh', 'ooooooo', 'nnnnnnn']
[1, 3, 5]
[(0, 25), (0, 100), (1, 25), (1, 100), (2, 25), (2, 100)]
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12, 13, 14], [15, 16, 17], [18, 19, 20]]
for
循环其实可以同时使用两个甚至多个变量,比如dict
的items()
可以同时迭代key和value:
>>> d = {'x': 'A', 'y': 'B', 'z': 'C' } >>> for k, v in d.items(): ... print(k, '=', v) ... y = B x = A z = C
因此,列表生成式也可以使用两个变量来生成list:
>>> d = {'x': 'A', 'y': 'B', 'z': 'C' } >>> [k + '=' + v for k, v in d.items()] ['y=B', 'x=A', 'z=C']
if ... else
跟在for
后面的if
是一个筛选条件,不能带else
,否则如何筛选?
for
前面的部分是一个表达式,它必须根据x
计算出一个结果。因此,表达式:x if x % 2 == 0
,它无法根据x
计算出结果,因此缺少else
,必须加上else
总结:在一个列表生成式中,for
前面的if ... else
是表达式,而for
后面的if
是过滤条件,不能带else
注意
列表推导式有自己的局部作用域,就像函数似的.表达式内部的变量和赋值只在局部起作用,表达式的上下文里的同名变量还可以被正常引用,局部变量并不会影响到它们.
也就是说,列表推导不会有变量泄漏的问题,在列表推导中的赋值操作不可能会影响到列表推导上下文中的同名变量.
也不是所有场景都推荐使用列表推导式.比如说:如果列表推导的代码超过了两行,就要考虑改成用for循环了.超过了两行的列表推导式就真的没有可读性了.通常的原则是,只用列表推导来创建新的列表,并且尽量保持简短.
字典推导式
# 因为key唯一,所以最后value都是1 被最后一个值覆盖 dict_a = {key: value for key in 'python' for value in range(2)} print(dict_a) # 可以根据键来构造值 dict_b = {key: key * key for key in range(6)} print(dict_b) # 遍历一个有键值关系的可迭代对象 list_phone = [('HUAWEI', '华为'), ('MI', '小米'), ('OPPO', 'OPPO'), ('VIVO', 'VIVO')] dict_c = {key: value for key, value in list_phone} print(dict_c)
#输出结果
{'p': 1, 'y': 1, 't': 1, 'h': 1, 'o': 1, 'n': 1}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
{'HUAWEI': '华为', 'MI': '小米', 'OPPO': 'OPPO', 'VIVO': 'VIVO'}
集合推导式
# 遍历一个可迭代对象生成集合 set_a = {value for value in '有人云淡风轻,有人负重前行'} print(set_a) #结果 {'负', '有', '人', '轻', '前', '云', '重', ',', '淡', '风', '行'}
集合是无序且不重复的,所以会自动去掉重复的元素,并且每次运行显示的顺序不一样.
参考 https://blog.csdn.net/weixin_43790276/article/details/90247423
https://www.liaoxuefeng.com/wiki/1016959663602400/1017269809315232
4.迭代器