廖雪峰Python教程学习笔记(3)

6. 高级特性

Python 的高级特性有助于我们写出简单、少量的代码。

6.1 切片

在 Python 中,listtuplestr 都可以使用切片操作。通过切片操作,可以取出部分元素,例如取出指定索引区域的元素,按一定间隔取出元素。特别地,对于 str 而言,切片操作就起到了截取的作用。

# 取 list 或者 tuple 的部分元素
L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']
print(L)
# 取出前 3 个元素
print([L[0], L[1], L[2]]) # ['Michael', 'Sarah', 'Tracy']

# 取出前 N 个元素
n = 4
r = []
for i in range(n):
    r.append(L[i])
print(r)

# 使用 slice 操作符

# L[0:3] 表示从 L 的索引 0 开始取,到索引 3 结束,但是不包括索引 3,也就是说取索引 0,1,2 这 3 个元素。
print(L[0:3]) # ['Michael', 'Sarah', 'Tracy']
# 如果是从索引 0 开始,可以省略开始索引
print(L[:3]) # ['Michael', 'Sarah', 'Tracy']
# 如果是取到尾部,可以省略尾部索引
print(L[1:]) # ['Sarah', 'Tracy', 'Bob', 'Jack']
# 支持倒数切片
# 从倒数第 2 个开始,取完。
print(L[-2:]) # ['Bob', 'Jack']
# 从倒数第 2 个开始,取到倒数第 1 个
print(L[-2:-1]) # ['Bob']

print(L[3:0]) # []
print(L[-1:-2]) #[]

# 切片操作进一步学习
L = list(range(100))
print(L)
# 取出前 10 个数
print(L[:10]) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 取出后 10 个数
print(L[-10:]) # [90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
# 前 11 到 20 个数
print(L[11:20]) # [11, 12, 13, 14, 15, 16, 17, 18, 19]
# 前 10 个数,每两个取一个
print(L[:10:2]) # [0, 2, 4, 6, 8]
# 所有数,每五个取一个
print(L[::5]) # [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]
# 复制一个 list
print(L[:])

# tuple 使用切片操作后,结果仍是 tuple
print((0, 1, 2, 3, 4, 5)[:3]) # (0, 1, 2)

# 字符串使用切片操作,结果仍是字符串
print('ABCDEF'[:3]) # ABC
print('ABCDEF'[::2]) # ACE

需要注意的是,切片操作都是从小索引,到大索引的;反过来,却不行。

6.2 迭代

在 Python 中,任何可迭代对象都可以作用于 for 循环,包括 listtupledictstr ,还包括自定义的可迭代对象。

# 迭代 list
L = [1, 3, 5, 7, 9]
for num in L:
    print(num)

# 迭代 tuple
T = ('a', 'b', 'c', 'd')
for ch in T:
    print(ch)

# 迭代 dict
D = {'name' : 'wangzhichao', 'age' : 18}
# 迭代 dict 中的 key, 这也是默认情况
for key in D:
    print(key)
# 迭代 dict 中的 value
for value in D.values():
    print(value)
# 同时迭代 dict 中的 key 和 value
for k, v in D.items():
    print(k, '->', v)

# 迭代字符串
for ch in 'ABC':
    print(ch)

# 判断一个对象是否是可迭代对象
from collections import Iterable

print(isinstance('abcde', Iterable)) # True
print(isinstance([1, 2, 3], Iterable)) # True
print(isinstance(1234, Iterable)) # False

# 对 list 实现下标迭代
for index, value in enumerate(['A', 'B', 'C']):
    print(index, value)

enumerate() 函数:这是一个内置函数,可以把一个 可迭代对象变成索引-元素对。Return an enumerate object. iterable must be a sequence, an iterator, or some other object which supports iteration。
Iterable 表示一个可迭代对象。

6.3 列表生成式

列表生成式,即 List Comprehensions,是 Python 内置的简单却强大的用来创建 list 的生成式。

# 生成 [1x1, 2x2, 3x3, ..., 10x10]
print([x * x for x in range(1, 11)]) # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

看一下上面例子中列表生成式的写法:x * x 是要生成的元素,放在最前面;然后,接着是一个 for 循环,这样就把需要的 list 创建了出来。

下边是列表生成式的演示代码:

# 生成 1 到 10 偶数的平方的 list
print([x * x for x in range(1, 11) if x % 2 == 0]) # [4, 16, 36, 64, 100]

# 使用两层循环,生成全排列
print([m + n for m in 'ABC' for n in 'XYZ']) # ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']

# 列出当前目录下的所有文件和目录名
import os # 导入 os 模块
print([d for d in os.listdir('.')]) # ['do_iter.py', 'do_iter_test.py', 'do_listcompr.py', 'do_slice.py', 'do_slice_test.py']

# 使用两个变量来生成list
print([k + '=' + v for k, v in {'x' : 'A', 'y' : 'B', 'z' : 'C'}.items()]) # ['x=A', 'y=B', 'z=C']

# 把一个list中所有的字符串变成小写
L = ['Hello', 'World', 'Adups', 'Abup']
print([s.lower() for s in L]) # ['hello', 'world', 'adups', 'abup']

需要注意的是,列表生成式中的 forif 不再使用 :,还有 continue 不能用在 for语句中了。

扫描二维码关注公众号,回复: 9458039 查看本文章

6.4 生成器

通过列表生成式,可以直接创建一个列表。但是,如果列表生成式一次生成的数据量太大,比如 100 万条,就会占据不小的内存。
如果列表元素可以按照某种算法推算出来,我们就可以在循环的过程中不断推算出后续的元素了。这样就不必一次创建很大的集合,从而节省内存空间。在 Python 中,就存在这种一边循环一边计算的机制,这就是生成器:generator。
创建一个 generator,有两种方法:
第一种方法:只要把一个列表生成式的 [] 改成 (),就创建了一个 generator。

# 创建一个 generator
L = [x * x for x in range(10)]
print(L) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
g = (x * x for x in range(10))
print(g) # <generator object <genexpr> at 0x00000000024E3510>

取出 generator 中的元素,可以通过 next() 函数。这里需要说明一下 next() 函数是一个内置函数。

next(iterator[, default])
Retrieve the next item from the iterator by calling its __next__() method. If default is given, it is returned if the iterator is exhausted, otherwise StopIteration is raised.
从迭代器里获取下一个元素。如果 default 参数被指定了,那么当迭代器迭代完时就返回指定的 default 值,否则就会抛出 StopIteration 异常。

print(next(g)) # 0
print(next(g)) # 1
print(next(g)) # 4
print(next(g)) # 9 
print(next(g)) # 16
print(next(g)) # 25
print(next(g)) # 36
print(next(g)) # 49
print(next(g)) # 64
print(next(g)) # 81
# print(next(g)) # 报错
'''
Traceback (most recent call last):
  File "do_generator.py", line 17, in <module>
    print(next(g))
StopIteration
'''

使用 next() 函数取出 generator 中的元素并不优雅,好的方式是使用 for 循环,因为 generator 也是一个 Iterable 对象。

g = (x * x for x in range(10))
print(isinstance(g, Iterable)) # True
for n in g:
    print(n)
'''
打印结果:
True
0
1
4
9
16
25
36
49
64
81
'''

第二种方法:使用函数来实现,这种方法适用于推算的算法比较复杂,用类似列表生成式的 for 循环不能实现的情形。

这里以斐波那契数列为例来说明:

斐波那契数列的起源
兔子问题:“假定一对大兔子每月能生一对小兔子,且每对新生的小兔子经过一个月可以长成一对大兔子,具备繁殖能力,如果不发生死亡,且每次均生下一雌一雄,问一年后共有多少对兔子?”

# 先用函数实现斐波那契数列
def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        print(b)
        a, b = b, a + b
        n = n + 1
    return 'done'

fib(6)

上面代码中的 a, b = b, a + b 等价于

t = (b, a + b) # t是一个tuple
a = t[0]
b = t[1]

毋庸置疑地,a, b = b, a + b 这种写法更加简洁,因为我们可以不写临时变量 t

好了,那么怎样把上面的函数 fib() 变成一个 generator 呢?
只要把 fib() 函数中的 print(b) 改成 yield b ,就 ok 了。

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

调用一下:

f = fib2(6)
print(f) # <generator object fib2 at 0x00000000026682E0>
for x in f:
    print(x)
'''
打印:
1
1
2
3
5
8
'''

这里涉及了一个新的关键字:yield。需要好好理解一下这个概念。
我们知道函数是顺序执行的,遇到 return 语句或执行到函数最后一行语句时,函数就会返回。但是,generator 却有些区别:generator 在每次调用 next() 函数的时候,遇到 yield 语句就返回;下次再调用 next() 函数的时候,从上次返回的 yield 语句处继续执行。

获取 generator 的返回值:

# 获取 generator 的返回值
g = fib2(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
'''

6.5 迭代器

看到迭代器,可能会想到之前学习的 Iterable,但是不能把两者混为一谈:

Iterable 是可迭代对象,指可以直接作用于 for 循环的对象。
Iterator 才是迭代器,指可以被 next() 函数调用并不断返回下一个值的对象。

那么,有哪些对象是 Iterable 对象,又有哪些对象是 Iterator 对象呢?
Iterable 对象主要包括两类:

  • 一类是集合类数据类型,如 listtupledictsetstrbytesrange 等;
  • 一类是生成器,包括类似列表生成式的生成器和带 yield 的生成器函数。
# 判断对象是否是 Iterable 对象
from collections.abc import Iterable, Iterator
print(isinstance([], Iterable)) # True, 说明 list 是 Iterable 对象
print(isinstance((), Iterable)) # True,说明 tuple 是 Iterable 对象
print(isinstance({}, Iterable)) # True,说明 dict 是 Iterable 对象
print(isinstance({1, 2, 3}, Iterable)) # True,说明 set 是 Iterable 对象
print(isinstance('hello', Iterable)) # True,说明 str 是 Iterable 对象
print(isinstance(b'hello', Iterable)) # True, 说明 bytes 是 Iterable 对象
print(isinstance(range(10), Iterable)) # True, 说明 range 是 Iterable 对象

g = (x * x for x in range(10))
print(isinstance(g, Iterable)) # True,说明生成器是 Iterable 对象
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(6)
print(isinstance(f, Iterable)) # True,说明生成器是 Iterable 对象

生成器都是 Iterator 对象,但 listdictstr 等虽是 Iterable,却不是 Iterator。通过使用 iter() 函数可以把 listdictstrIterable 转成 Iterator

# 判断对象是否是 Iterator 对象
print(isinstance([], Iterator)) # False, 说明 list 不是 Iterator 对象
print(isinstance((), Iterator)) # False,说明 tuple 不是 Iterator 对象
print(isinstance({}, Iterator)) # False,说明 dict 不是 Iterator 对象
print(isinstance({1, 2, 3}, Iterator)) # False,说明 set 不是 Iterator 对象
print(isinstance('hello', Iterator)) # False,说明 str 不是 Iterator 对象
print(isinstance(b'hello', Iterator)) # False, 说明 bytes 不是 Iterator 对象
print(isinstance(range(10), Iterator)) # False, 说明 range 不是 Iterator 对象

g = (x * x for x in range(10))
print(isinstance(g, Iterator)) # True,说明生成器是 Iterator 对象
def fib2(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
    return 'done'
f = fib2(6)
print(isinstance(f, Iterator)) # True,说明生成器是 Iterator 对象

print('*' * 20)

# 把集合类数据类型转为 Iterator
print(isinstance(iter([]), Iterator)) # True
print(isinstance(iter(()), Iterator)) # True
print(isinstance(iter({}), Iterator)) # True
print(isinstance(iter({1, 2, 3}), Iterator)) # True
print(isinstance(iter('hello'), Iterator)) # True
print(isinstance(iter(b'hello'), Iterator)) # True
print(isinstance(iter(range(10)), Iterator)) # True

需要说明一下,iter() 函数是 Python 的内置函数,它的作用是返回一个 Iterator 对象。

发布了78 篇原创文章 · 获赞 46 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/willway_wang/article/details/104235198