在python中,我们所拥有以下几种非常有用的高级特性能够使我们在编写代码的过程中,使我们的代码量大大减少。

- 切片(Slice)

切片常用于从某个对象中抽取部分值的情况,只要条件表达式得当,可以通过单次多次切片操作实现任意目标值切取。 如果你想尽快知道list(range(1,21))实现原理,可以先观看本章的列表生成器部分。

L = list(range(1,21))   #自定义一个列表,存入有序数列1-20共二十个数
print(L)   #打印列表L
print(type(L))  #打印列表类型
print(L[0:5])  #打印列表前五个值即下标为0-4,[0:5]表示从索引0开始,直到索引5结束,但不包括索引3
print(L[:5])  #与上条功能相同,表达式更简便
print(L[17:20])  #打印列表最后三位数字即下标为17,18,19的三位数。[17:20]表示从索引17开始,直到索引20结束,但不包括索引20。
print(L[-3:])   #与上条功能相同,表达式更简便
print(L[:10:5])  #列表的前十个数中,每五个数取一个值
print(L[::5])   #列表的所有数中,每五个数从中取一个

打印为:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
<class 'list'>
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
[18, 19, 20]
[18, 19, 20]
[1, 6]
[1, 6, 11, 16]

tuple也是list的一种,区别是tuple不可变,所以tuple也是可以使用切片操作,不过结果仍是tuple字符串‘ XXX ‘也可以看成一种list,不过每一个字符就是一个元素,所以字符串也是可以使用切片操作,不过结果仍是字符串

T = (1,2,3,4,5,6,7,8,9,10)  #创建一个tuple
print(T)  #打印tuple
print(T[:])  #[:]效果与本身相同
print(T[:3])  #打印tuple前三个值
print(type(T[:]))  #打印tuple切片后获取到的数据的数据类型

S = "Python"  #创建一个字符串
print(S[:3])  #切片获取前三个值,即组合成的新的字符串
print(type(S[:]))  #获取字符串切片后的数据的数据类型

打印为:

(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
(1, 2, 3)
<class 'tuple'>
Pyt
<class 'str'>

- 迭代(Iteration)

如果给定一个list或tuple等,我们可以通过for循环进行遍历,这种遍历我们叫做迭代。在Python迭代是通过for...in...来完成的。 我们判断一个对象是不是迭代对象可以引用 collections.abc 模板下的Iterable。例如:

#导入
from collections.abc import Iterable

L = list(range(5))  #创建数组
print(isinstance(L,Iterable))  #判断数组 L 是否是可迭代对象并打印出来
print(isinstance('abc',Iterable))  #判断 字符串'abc' 是否是可迭代对象并打印出来
# 遍历数组L,并打印
for value in L:
    print(value)

打印为:

True
True
0
1
2
3
4

对于dict我们也可以进行迭代,但由于键值对我们默认迭代key,如果想要迭代value我们可以使用dict.values(),如果想要同时迭代keyvalue我们则需要使用dict.items()

d = {"Join": "蛋糕", "Tom": "雪糕"}  #创建dict
print("-----只迭代key-----")
for key in d:
    print(key)
print("-----只迭代value-----")
for value in d.values():
    print(value)
print("-----同时迭代key和value-----")
for k,v in d.items():
    print("key : " + k , "\tvalue:" , v)

打印结果为:

-----只迭代key-----
Join
Tom
-----只迭代value-----
蛋糕
雪糕
-----同时迭代key和value-----
key : Join  value: 蛋糕
key : Tom   value: 雪糕

像我们刚刚迭代dict,能够同时获取两个值,其实,元素对返回的是一个元组数据,所以可以我们拆分多个变量去接,方便我们同时引用多个变量

for x, y in [(1, 'a'), (2, 'b'), (3, 'c')]:
    print('x =', x, 'y =', y)

打印为:

x = 1 y = a
x = 2 y = b
x = 3 y = c

如果我们想要获取到迭代对象的下标,我们可以使用Python内置的enumerate函数把它变成索引-元素对,这样我们就可以同时迭代索引元素对本身。

#迭代dict,默认只迭代key值
for i, key in enumerate({"Join": "蛋糕", "Tom": "雪糕"}):
    print('i =', i, 'key =', key)

打印为:

i = 0 key = Join
i = 1 key = Tom

- 列表生成式

列表生成式List Comprehensions,是Python内置的非常简单却强大的可以用来创建list生成式。 例如:

L1 = list(range(1,10))
L2 = list(range(0,10))
L3 = list(range(10))  #等同第二个
print(L1)
print(L2)
print(L3)

打印为:

[1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

当然列表生成器还有更多略微复杂的操作,如果要生成[1x1, 2x2, 3x3, …, 10x10]怎么做?方法一是循环,方法二则是我们使用列表生成器代替循环,例如:

L1 = []
# 方法一:使用for循环,每次循环都在列表结尾进行追加
for x in range(1,11):
    L1.append(x * x)
#方法二:列表生成器
L2 = [a * a for a in range(1,11)]
print(L1)
print(L2)

打印为:

[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

我们甚至可以进行更多操作:

# 创建成功列表后在判断进行取出源列表内的所有偶数集
L1 = [x * x for x in range(1,11) if x % 2 == 0]
#有if那么我们肯定就有else语句
L2 = [x * x if x % 2 == 0 else 0 for x in range(1,11)]
#从第一个字符串中挨个取出作为x,从第二个字符串中挨个取出作为y,并进行组合排列
L3 = [x + y for x in '唱跳R' for y in '吃喝玩']
#把list中的所有字符串都变成小写
L4 = ['Boy','Girl','IBM']
L4 = [s.lower() for s in L4]
print(L1)
print(L2)
print(L3)
print(L4)

打印为:

[4, 16, 36, 64, 100]
[0, 4, 0, 16, 0, 36, 0, 64, 0, 100]
['唱吃', '唱喝', '唱玩', '跳吃', '跳喝', '跳玩', 'R吃', 'R喝', 'R玩']
['boy', 'girl', 'ibm']

- 生成器

  • 什么是生成器 在Python中,一边循环一边计算的机制,称为生成器generator。并且生成器仅仅保存了一套生成数值的算法,并且没有让这个算法现在就开始执行而是我什么时候调它,它什么时候开始计算一个新的值
  • 为什么要有生成器 如果列表元素按照某种算法推算出来,那我们就可以在循环的过程中不断推算出后续的元素,这样就不必创建完整的list,从而节省大量的空间。如果我们想要得到庞大的数据,又想让它占用空间少,那我们最好的方法就是使用生成器。 并给你返回。

我们创建一个generator只需要把列表生成式的[]改为()就可以。

g = (x for x in range(1,11))  #创建一个generator
print(g)  #打印
print(type(g))  #打印其类型
print("-----使用next()获取generator的每一个值-----")
#打印g的元素,next()只可以返回获得generator的下一个返回值,所以我们如果一直使用next()函数获取generator的每一个值会非常麻烦也不现实
print(next(g))
print(next(g))
print(next(g))
print("------使用for循环获取generator的每一个值-----")
for i in g:
    print(i)

打印结果为:

<generator object <genexpr> at 0x10fd64750>
<class 'generator'>
-----使用next()获取generator的每一个值-----
1
2
3
------使用for循环获取generator的每一个值-----
4
5
6
7
8
9
10

如果算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
    return 'done'

f = fib(5)
print(f)

打印为:

<generator object fib at 0x10353a750>

如果一个函数包含yield关键字,那么这个函数不再是一个普通函数,是一个generator。generator的函数,在每次调用next()的时候执行,遇到yield语句返回再次执行上次返回的yield语句处继续执行

- 迭代器

  • 生成器都是迭代器,而基本数据集合不属于迭代器,区别在于能不能使用next(), 可以用iter([])来讲基本集合类型转化为迭代器
  • 迭代器对象无法预知集合的长度,是一个在调用的时候才能获取到对应位置对象的惰性计算对象,是一种流的形式
  • Python的for循环本质上就是通过不断调用next()函数实现的,
  • Iterable 迭代类型 Iterator 迭代器