ShannonChenCHN / APythonTour

Yes, beautiful is better than ugly.
MIT License
0 stars 2 forks source link

3.5 Python 基础语法之高级特性 #4

Open ShannonChenCHN opened 6 years ago

ShannonChenCHN commented 6 years ago

日期:2018.07.10 周二

ShannonChenCHN commented 6 years ago

切片(Slice)

List

有了切片(Slice)操作,很多需要取指定索引范围的地方,就不再需要循环来实现了。Python的切片非常灵活,一行代码就可以实现很多行循环才能完成的操作。

L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']

取前 3 个:

>>> L[0:3]
['Michael', 'Sarah', 'Tracy']

前 5 个中,每隔一个取一个

>>> L[:5:2]
['Michael', 'Tracy', Jack']

Tuple

tuple也是一种list,唯一区别是tuple不可变。因此,tuple也可以用切片操作,只是操作的结果仍是tuple。

T = (0, 1, 2, 3, 4, 5)
>>> T[:3]
(0, 1, 2)

字符串

字符串 'xxx' 也可以看成是一种 list,每个元素就是一个字符。因此,字符串也可以用切片操作,只是操作结果仍是字符串。(不同于其他语言,Python 没有针对字符串的截取函数,只需要切片一个操作就可以完成)

>>> 'ABCDEFG'[:3]
'ABC'
>>> 'ABCDEFG'[::2]
'ACEG'

参考

ShannonChenCHN commented 6 years ago

迭代(Iteration)

如果给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历我们称为迭代(Iteration)。

任何可迭代对象都可以作用于for循环,包括我们自定义的数据类型,只要符合迭代条件,就可以使用for循环。在Python中,迭代是通过for ... in来完成的。

字典

默认情况下,dict迭代的是key。

d = {'a': 1, 'b': 2, 'c': 3}
for key in d:
    print(key, ':',  d[key])

for value in d.values():
    print(value)

for key, value in d.items():
    print(key, ':', value)

字符串

字符串也是可迭代对象:

for c in 'English':
    print(c)

数组

for num in [2, 56, 23]:
    print(num)

# Python内置的enumerate函数可以把一个list变成索引-元素对
for i, value in enumerate([3, 56, 23]):
    print(i, value)

for x, y in [(1, 1), (2, 3), (5, 8)]:
    print(x, y)

Iterable

如何判断一个对象是可迭代对象呢?方法是通过collections模块的Iterable类型判断:

from collections.abc import Iterable

print(isinstance('abc', Iterable))
print(isinstance([1, 2, 3], Iterable))
print(isinstance(123, Iterable))

参考

ShannonChenCHN commented 6 years ago

列表生成式(List Comprehensions)

什么是列表生成式?

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

运用列表生成式,可以快速生成 list,可以通过一个 list 推导出另一个 list,而代码却十分简洁。

个人理解:列表生成式的作用有点类似于高阶函数,给定一个 list,提供一个变换操作或者筛选条件,生成一个新数组。

示例代码

L1 = list(range(1, 11))
print(L1)

L2 = [x * x for x in range(1, 11)]
print(L2)

使用筛选条件:

L3 = [x * x for x in range(1, 11) if x % 2 == 0]
print(L3)

使用双循环:

L4 = [m + n for m in 'ABC' for n in 'XYZ']
print(L4)

使用两个变量来生成 list:

d = {'baidu': 'www.baidu.com', 'tencent': 'www.qq.com', 'amazon': 'www.amazon.com'}
[k + '=' + v for k, v in d.items()]
print(d)

大写转小写:

L5 = ['Hello', 'World', 'IBM', 'Apple']
L5_lower = [s.lower() for s in L5]
print(L5_lower)

打印当前目录下的所有文件名:

import os
ls = [d for d in os.listdir('.')]
print(ls)
ShannonChenCHN commented 6 years ago

生成器(Generator)

在Python中,这种一边循环一边计算的机制,称为生成器(generator)。

创建生成器的两种方法

1. 只要把一个列表生成式的 [] 改成 (),就创建了一个生成器:

g = (x * x for x in range(10))
print(g)  # <generator object <genexpr> at 0x101240c00>

print(g.__next__())
print(next(g))
print(next(g))
print(next(g))
print(next(g))

# 可以使用 for 循环遍历生成器,因为generator也是可迭代对象。
for n in g:
    print(n)

可以使用 for 循环遍历生成器,因为generator也是可迭代对象。

2. 通过定义一个包含 yield 关键字的函数来创建生成器:

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

for i in fib(6):
    print(i)
# 打印结果: 1 1 2

如果一个函数定义中包含 yield 关键字,那么这个函数就不再是一个普通函数,而是一个generator。

在执行过程中,遇到 yield 就中断执行并返回,再次执行时从上次返回的 yield 语句处继续执行,直到已经没有yield 可以执行了,再调用 next(o) 就会报错。

generator 的工作原理

普通函数和 generator 函数的区别:

参考

ShannonChenCHN commented 6 years ago

迭代器(Iterator)

可迭代对象 VS. 迭代器

可迭代对象

可以直接作用于 for 循环的数据类型有以下几种:

这些可以直接作用于for循环的对象统称为可迭代对象(Iterable)

生成器

生成器不但可以作用于for循环,还可以被 next() 函数不断调用并返回下一个值,直到最后抛出StopIteration 错误表示无法继续返回下一个值了。

可以被 next() 函数调用并不断返回下一个值的对象称为迭代器(Iterator)

几个知识点

为什么list、dict、str等数据类型不是Iterator?

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被 next() 函数调用并不断返回下一个数据,直到没有数据时抛出 StopIteration 错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以 Iterator 的计算是惰性的,只有在需要返回下一个数据时它才会计算

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

如何让自定义类也具备 Iterator 特性?

跟 Objective-C 中实现 NSFastEnumeration 协议就可以支持快速枚举类似,在 Python 中,实现 iterator 协议的 __iter__ 方法和 __next__ 方法,即可让自定义类也具备 Iterator 特性:

class Reverse:
    """Iterator for looping over a sequence backwards."""
    def __init__(self, data):
        self.data = data
        self.index = len(data)

    def __iter__(self):
        return self

    def __next__(self):
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]
>>> rev = Reverse('spam')
>>> iter(rev)
<__main__.Reverse object at 0x00A1DB50>
>>> for char in rev:
...     print(char)
...
m
a
p
s

参考