370-Python高级语法
- with语句:上下文管理器
- 上文管理器:open
- 下文管理器:close
- yield生成器(掌握两种创建方式)
- 类似推导式结构
- 大大降低程序能耗
- 深浅拷贝
- 面试考的多:深拷贝和浅拷贝的区别
- 正则表达式
写在前面
老的文件操作方法:
# 写入模式打开文件
f = open("1.txt", "w")
# 写入文件内容
f.write("Ikun")
# 关闭文件
f.close()
文件在使用完后必须关闭,因为文件对象会占用操作系统资源,并且操作系统同一时间能打开的文件数量也是有限的(linux内核信息定义的最大打开文件数是1024)
老方法存在的问题:
#1、以读的方式打开文件
f = open("1.txt", "r") # 只读模式
#2、写入文件内容
f.write("Ikun") # 但是写入文件
#3、关闭文件
f.close()
由于文件读写时都有可能产生IOError,一旦出错,后面的f.close()就不会调用,这里就会造成资源浪费(会占用系统资源)
对此问题,可以用try...except...语句来解决
但是最好的方案是使用with语句(高级语法,代码简化)
with语句和上下文管理器
上下文管理器和with语句的定义
- 上下文管理器:上下文管理器是Python中的一个协议,用于管理资源的生命周期,例如文件的打开和关闭、数据库的连接和断开等
- with语句:with语句用于管理上下文管理器,在文件操作中,with语句可以自动管理文件的打开和关闭,避免忘记关闭文件导致资源泄露
Python提供了 with 语句的写法,既简单又安全。
文件操作的时候使用with语句可以自动调用关闭文件操作,即使出现异常也会自动关闭文件操作。
使用with方法实现文件操作,如下所示:
# 1、以写的方式打开文件
with open('1.txt', 'w') as f:
# 2、读取文件内容
f.write('Ikun')
上下文管理器
当使用with语句后,就会自动创建上文管理器(__enter()__
)和下文管理器(__exit()__
)
__enter()__
:f = open("1.txt", "w")
__exit()__
:f.close()
生成器是什么
根据程序设计者制定的规则循环生成数据,当条件不成立时则生成数据结束
作用
数据不是一次性全部生成出来,而是使用一个,再生成一个,可以节约大量的内存,降低程序运行消耗时间。
创建生成器的方式
① 推导式 生成器
② yield 关键字生成器
推导式生成器
与列表推导式类似,只不过生成器推导式使用小括号。
109-推导式(数据容器)
# 创建生成器
my_generator = (i * 2 for i in range(5))
print(my_generator)
(i * 2 for i in range(5))
是生成器
[i * 2 for i in range(5)]
是直接生成现成的列表
(i * 2 for i in range(5))
本质是一个对象,其中没有02468这些数据,只有数据生成的规则
如果打印my_generator
,那么打印的只是这个对象的内存地址
# next 获取生成器下一个值
value = next(my_generator)
print(value)
- 使用next()函数获取生成器的元素:
生成器中有一个关键的函数:next(),每调用一次就会根据规则创建一个元素,然后向后移动,再次调用next()函数就会再生成一个元素
# 遍历生成器
for value in my_generator:
print(value)
- for 循环遍历生成器中的每一个值
yield生成器
yield生成器是啥
重点理解yield生成器的执行流程
yield生成器结构:
- 定义一个函数
- 函数内部存在一个yield关键字
yield 关键字生成器的特征:在def函数中具有yield关键字
当函数和yield组合在一起就叫做生成器,这个函数就不是函数了,就转变成了对象
代码演示:
用next函数获取生成器的元素
def generator(n):
for i in range(n):
print('开始生成数据')
yield i # 暂时可以把yield当成return理解,每次遇到yield,生成器就相当于执行一次(生成循环执行到yield后就暂停,后面在调用就从这里继续执行,意思就是'完成一次数据生成'这句话会在第二次生成的时候打印)
print('完成一次数据生成')
# 使用时,由于生成器需要传递参数,所以通常将其赋予给某个变量
g = generator(5)
# 如果print(generator(5)),输出的是对象的内存地址
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g)) -----> 正常
print(next(g)) -----> 报错
Traceback (most recent call last):
File "/Users/cndws/PycharmProjects/pythonProject/demo.py", line 14, in <module>
print(next(g))
StopIteration(到达边界)
但是这里执行第六次next()会把'完成一次数据生成'这句打印出来
用for循环遍历生成器的元素
for循环的好处:可以避免上面出现的到达边界的错误
def generator(n):
for i in range(n):
print('开始生成...')
yield i
print('完成一次...')
g = generator(5)
for i in g:
print(i)
使用while循环+try...except语句获取生成器元素
这样同样可以避免到达边界的错误
def generator(n):
for i in range(n):
print('开始生成...')
yield i
print('完成一次...')
g = generator(5)
while True:
try:
print(next(g))
except StopIteration:
break
yield关键字和return关键字
如果不太好理解yield
,可以先把yield
当作return
的同胞兄弟来看,他们都在函数中使用,并履行着返回某种结果的职责。
这两者的区别是:
有return
的函数直接返回所有结果,程序终止不再运行,并销毁局部变量;
def example():
x = 1
return x
example = example()
print(example)
而有yield
的函数则返回一个可迭代的 generator(生成器)对象,你可以使用for循环或者调用next()方法遍历生成器对象来提取结果。
def example():
x = 1
y = 10
while x < y:
yield x
x += 1
example = example()
print(example)
生成器的现实应用案例
斐波那契数列:数学中的一个概念,是一组有规律的数字!
1 1 2 3 5 8 13 21 34 55 ...
规律:
隐藏了一个元素 => 0
第1个元素为1
第2个元素为1,第2个元素为1,实际上是由0 + 1 = 隐藏元素 + 第一个元素
第3个元素为2 = 1 + 1,第3个元素值 = 第2个元素值 + 第1个元素值
第4个元素为3 = 2 + 1,第4个元素值 = 第3个元素值 + 第2个元素值
刚好满足:数据量比较大,而且还要经过大量的计算 => 符合生成器的使用规则
0 1 1 2 3 5 8 13 21 34 55 ...
a变量代表,斐波那契数列中前一个元素,比如a可以代表0
b变量代表,斐波那契数列中后一个元素,比如b可以代表1
a,b是相邻的两个元素
def fib(max): # 求max位斐波那契数列 => 前max位斐波那契数列的每个值
n, a, b = 0, 0, 1
while n < max:
yield b # 第一次循环,弹出一个1
# 想个办法,让第二次yield b,弹出一个1,第三次yield b,弹出一个2
# a = 0, b = 1
a, b = b, a + b
# a = 1, b = 1
n += 1
result = fib(50)
for i in result:
print(i)
使用生成器的注意事项:
① 代码执行到 yield 会暂停,然后把结果返回出去,下次启动生成器会在暂停的位置继续往下执行
② 生成器如果把数据生成完成,再次获取生成器中的下一个数据会抛出一个StopIteration 异常,表示停止迭代异常
③ while 循环内部没有处理异常操作,需要手动添加处理异常操作
④ for 循环内部自动处理了停止迭代异常,使用起来更加方便,推荐大家使用。