Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
ShannonChenCHN opened this issue Jul 10, 2018 · 5 comments
Open

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

ShannonChenCHN opened this issue Jul 10, 2018 · 5 comments

Comments

@ShannonChenCHN
Copy link
Owner

ShannonChenCHN commented Jul 10, 2018

日期:2018.07.10 周二

  • 切片
  • 迭代
  • 列表生成式
  • 生成器
  • 迭代器
@ShannonChenCHN
Copy link
Owner Author

ShannonChenCHN commented Jul 10, 2018

切片(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
Copy link
Owner Author

ShannonChenCHN commented Jul 10, 2018

迭代(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
Copy link
Owner Author

ShannonChenCHN commented Jul 10, 2018

列表生成式(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
Copy link
Owner Author

ShannonChenCHN commented Jul 10, 2018

生成器(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 保存的是算法,每次调用 next(g),就计算出 g 的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出 StopIteration 的错误。
  • generator 是在for循环的过程中不断计算出下一个元素,并在适当的条件结束for循环。对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。

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

  • 普通函数调用直接返回结果
  • generator 函数的“调用”实际返回一个 generator 对象

参考

@ShannonChenCHN
Copy link
Owner Author

ShannonChenCHN commented Jul 10, 2018

迭代器(Iterator)

可迭代对象 VS. 迭代器

可迭代对象

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

  • 一类是集合数据类型,如 listtupledictsetstr 等;
  • 一类是 generator,包括生成器和带 yield 的 generator function。

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

生成器

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

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

几个知识点

  • 可以使用 isinstance() 判断一个对象是否是 Iterable 对象
  • 可以使用 isinstance() 判断一个对象是否是 Iterator 对象
  • 凡是可作用于 next() 函数的对象都是 Iterator 类型,它们表示一个惰性计算的序列。
  • 集合数据类型如list、dict、str等是 Iterable 但不是Iterator,不过可以通过 iter() 函数获得一个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

参考

@ShannonChenCHN ShannonChenCHN changed the title 高级特性 3.5 Python 基础语法之高级特性 Jul 16, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant