【Python】高级特性
文章目录
- 概要
- 一、迭代器与推导式
- 1.1iter()函数
- 1.2可迭代对象的推导式
- 1.2.1 缩进嵌套
- 1.2.2 for语句的返回值
- 二、生成器
- 2.1 yield语句
- 2.2 惰性计算
- 3.2 回溯法和生成器应用
- 三、装饰器
- 3.1 函数嵌套和作用域关键字
- 3.1.1 函数嵌套
- 3.1.2 nonlocal与global
- 3.2 装饰器
- 四、上下文管理器
- 五、函数式编程
- 5.1 函数是一等类(first-class status)
- 5.2 高阶函数
- 5.2.1 作为参数的函数
- 5.2.2 作为返回值的函数
- 5.3 匿名函数
- 六、多线程和多进程
- 七、协程
- 八、类型注解
- 九、元编程
- 其他章节的内容
概要
本文讲解了Python的一些高级特性,包括迭代器推导式、生成器、装饰器、上下文管理器、函数式编程、多线程和多进程、协程、类型注解、元编程(其中函数式编程后的内容还在学习中,后续会进行更新)
一、迭代器与推导式
迭代器是一个表示数据流的对象,每次只返回一个元素。Python的迭代器必须支持__next()__方法,该方法不需要参数,且总是返回下一个元素。有__next()__方法的对象都可以通过内置函数iter()函数将其转化为迭代器。
1.1iter()函数
iter()函数的语法如下:
iter(object, [sentinel])
object是要转换的对象,sentinel是迭代条件,当迭代器返回的元素等于它时停止迭代。
1.2可迭代对象的推导式
对于任意迭代器都可以通过for语句构建推导式。
1.2.1 缩进嵌套
这种方式会统领冒号后面的缩进的代码块,可以对每一个元素进行操作如:
for element in list:
print(element)
1.2.2 for语句的返回值
这种方式一般用来生成列表字典集合甚至生成器,这种推导式返回的所有元素的定义域是后面for语句迭代出来的每一个元素,映射关系是前面的表达式。
# 生成列表
squared = [x ** 2 for x in range(10)]
# 生成字典
squared_dict = {x: x ** 2 for x in range(10)}
# 生成集合
squared_set = {x ** 2 for x in range(10)}
# 生成生成器
squared_gen = (x ** 2 for x in range(10))
二、生成器
生成器全称生成器函数,它使用yield返回值,这种返回方式使得他可以按需生成元素,十分节省内存。就普通函数而言,当程序运行到return时,会把后面的表达式返回并结束函数同时删除局部变量,但yield的作用是暂停函数,同时保留局部变量,在下一次调用生成器函数时继续运行,因而可以理解为该函数返回的是一个可迭代的数据流。
2.1 yield语句
yield有以下两种形式:
yield 表达式
yield from 生成器
第一种很好理解,这和普通函数的return一样,只不过yield返回完表达式不会将函数销毁。第二种的意思是从另一个生成器中接受返回值并返回,一种用法就是展平列表。
def flat(items):
for x in items:
if isinstance(x, list):
yield from flat(x)
else:
yield x
>>>In[0]:items = [1, 4, [3, 7, [5, 6], 8], 9]
>>>Out[0]:[1, 4, 3, 7, 5, 6, 8, 9]
2.2 惰性计算
当处理当文件时,yield有很独特的优势,由于yield每次只返回一个对象,而不是一次性将所有对象全部返回,这么做十分节省内存,因而被称作惰性计算
3.2 回溯法和生成器应用
对于复杂和大型的问题,常常可以使用回溯法进行求解,先假设某些条件当发现不满足解题条件时返回到上一个决策点更换策略。比如著名的八皇后问题,使用递归方式求解是这样的:
def check(board, x): # 检查摆盘是否有冲突
y = len(board)
for i in range(y):
if abs(board[i] - x) in (0, y - 1):
return False
return True
def queens(num=8, board=[]):
for col in range(num):
if check(board, col):
if len(board) == num - 1: # 产生解
board = board + [col]
result.append(board)
else:
board = board + [col]
queens(num, board)
del board[-1]
用生成器来实现是这样的:
def check(board, x): # 检查摆盘是否有冲突
y = len(board)
for i in range(y):
if abs(board[i] - x) in (0, y - 1):
return False
return True
def queens(num=8, board=[]):
for col in range(num):
if check(board, col):
if len(board) == num - 1: # 产生解
yield [col]
else:
for result in queens(num, board + [col]):
yield [col] + result
三、装饰器
装饰器是一个用来改变函数功能但是不修改原函数代码的工具,是代码更加简洁易懂,同时遵循了编程的“ 开放/关闭原则 ”。在讲装饰器之前,我们先来看看函数嵌套。
3.1 函数嵌套和作用域关键字
3.1.1 函数嵌套
在Python当中,允许函数嵌套,即在函数当中定义一个函数,这个内部函数是属于外部函数的,只能在外部函数内部调用。接下来我们来说说函数命名空间,Python标识符的查找按照LEGB的规则,即按照LEGB的顺序查找标识符的含义,他们的含义如下:
缩写 | 缩写含义 |
---|---|
L | 局部命名空间 |
E | 外部嵌套函数命名空间 |
G | 全局命名空间 |
B | 内置模块命名空间 |
由于内置函数是属于外部嵌套函数命名空间的,所以在外部函数之外的变量是无法访问内置函数的。
3.1.2 nonlocal与global
nonlocal:这个关键字表明这个标识符并非局部命名空间的变量,这个时候再使用该标识符,Python就不会认为你在创建一个新的局部变量而是调用了外部嵌套函数的变量。
global:这个关键字表明这个标识符是一个全局命名空间的变量,和nonlocal一样,Python会在全局命名空间中找这个变量而非新建一个变量。
3.2 装饰器
广义来说,任何能接收一个函数作为参数,且返回一个函数的函数都可以作为装饰器被使用。装饰器函数的本质就是,将要装饰的函数(func)作为参数传给装饰器(deco),同时调用这个返回的函数(wrapper)。装饰器函数一般定义如下:
def deco(func):
def wrapper(*args, **argv):
do something
return wrapper
一般func也会在wrapper中被调用,否则这个装饰器就没有意义了。
四、上下文管理器
上下文管理器是一个对象,他在执行with语句时建立上下文环境,在进入或者离开的时候调用__enter__()函数或者__exit__()函数,这么做可以有效地管理资源。由于Python提供的内置模块contextlib的存在,使得我们可以很轻松地重新定义上下文管理器with。首先with语句的核心逻辑如下:
try:
fread = open('file path', read mode)
finally:
fread.close()
contextlib只是使我们不需要关注__enter__()函数和__exit__()函数,只需要实现with语句所做的事情就好,因而使用装饰器自定义上下文管理器可以这么做:
from contextlib import contextmanager
@ contextmanager
def with(file_path, read_mode):
try:
fread = open(file_path, read_mode)
yield fread
finally:
fread.close()
在自定义上下文管理器的时候我们用到了装饰器,生成器。装饰器的作用是自动准备好__enter__()函数和__exit__()函数,生成器的目的是在返回打开的文件对象后不关闭文件,而是在退出上下文管理器的时候再执行后面的语句。这个自定义的上下文管理器中也可以加一些其他的东西,比如文字描述当前程序进程,看你喜欢。
五、函数式编程
5.1 函数是一等类(first-class status)
函数编程的第一个要点是一个偏向思维和概念的东西,在实际编程中用不到,但却对思维的改变有莫大的帮助。Python的函数是作为第一等级的类来看待的,既然是类那他就有如下性质:
- 可以存储在多个变量名中
- 可以作为参数传递给函数
- 可以作为返回值,从函数中返回
- 可以作为元素存储在数据结构中
5.2 高阶函数
5.2.1 作为参数的函数
思考以下三个计算求和的函数。第一个 sum_naturals 会计算从 1 到 n 的自然数之和:
>>> def sum_naturals(n):
total, k = 0, 1
while k <= n:
total, k = total + k, k + 1
return total
>>> sum_naturals(100)
5050
第二个 sum_cubes 函数会计算 1 到 n 的自然数的立方之和。
>>> def sum_cubes(n):
total, k = 0, 1
while k <= n:
total, k = total + k*k*k, k + 1
return total
>>> sum_cubes(100)
25502500
第三个 pi_sum 会计算下列各项的总和,它的值会非常缓慢地收敛(converge)到 π \pi π。
>>> def pi_sum(n):
total, k = 0, 1
while k <= n:
total, k = total + 8 / ((4*k-3) * (4*k-1)), k + 1
return total
>>> pi_sum(100)
3.1365926848388144
这三个函数显然在背后共享着一个通用的模板(pattern)。它们在很大程度上是相同的,仅在名称和用于计算被加项 k 的函数上有所不同。我们可以通过在同一模板中填充槽位(slots)来生成每个函数:
def <name>(n):
total, k = 0, 1
while k <= n:
total, k = total + <term>(k), k + 1
return total
5.2.2 作为返回值的函数
装饰器就是一个很好的返回值是函数的例子。对于这种函数,当你给外部函数传递参数后,可以理解为函数会完成部分初始话,同时返回里面的函数,当所有内嵌函数都传递完参数后,函数才会返回程序运行的结果。
5.3 匿名函数
匿名函数的语法是:
lambda x: experssion
这个表达式返回的是一个函数,这个函数需要一个x作为参数,它等价于直接定义函数。灵活应用高阶函数和匿名函数可以实现很多强大且简洁的功能,这需要在日常多家练习和理解,基本概念就这么多,能用成啥样全看个人的本事。
六、多线程和多进程
七、协程
八、类型注解
九、元编程
其他章节的内容
序列
集合与字典
函数
模块和包
异常
文件
类
高级特性