Python中的两个高级语法

今天就来简单介绍一下Python中的两个高级语法: with上下文管理器 和 yield生成器

with上下文管理器

为什么使用with语句???
1.文件操作:

文件使用完后必须关闭,因文件对象会占用操作系统的资源,并且操作系统同一时间能打开的文件数量也是有限的

# 1、以写的方式打开文件
 f = open("1.txt", "w")
 # 2、写入文件内容
 f.write("hello world")
 # 3、关闭文件
 f.close()
2.存在安全隐患

① 由于文件读写时都有可能产生IOError,一旦出错,后面的f.close()就不会调用。

② 为了保证无论是否出错都能正确地关闭文件,我们可以使用try ... finally来解决

 # 1、以读的方式打开文件
 f = open("1.txt", "r")
 # 2、写入文件内容
 f.write("hello world")
 # 3、关闭文件
 f.close()
3.try…except…finally解决文件操作异常

缺点:try-except-finally语句缺点:代码过于冗长, 不易用,易忘

try:
    # 1、以读的方式打开文件
    f = open("1.txt", "r")
    # 2、读取文件内容
    f.write("xxxxx")

except IOError as e:
    print("文件操作出错", e)

finally:
    # 3、关闭文件
    f.close()
4.with特点:

上下文管理器with语句:该机制简单、更安全的处理资源和异常          

特点:with 语句执行完成后,自动调用关闭文件操作,即使出现异常也会自动调用关闭文件操作

实例代码:
# 1、以写的方式打开文件
with open("1.txt", "w") as f:
    # 2、读取文件内容
    f.write("hello world")
with上下文管理器__一个例子:

一个类只要实现了__enter__()和__exit__()这个两个方法,通过该类创建的对象我们就称之为上下文管理器

_enter__表示上文方法,需要返回一个操作文件对象

__exit__表示下文方法,with语句执行完成会自动执行,即使出现异常也会执行该方法

"""
(1)写一个文件操作的上下文管理器,并用with语句测试通过

		a.要求增加一个read_data函数,读文件操作,只读前10行;

        b.提交代码和运行效果
"""
# 1. 自定义上下文管理器类.
class Func:
    # 2. 重写 __init__()魔法方法, 初始化: file_name(文件名), file_model(文件模型)
    def __init__(self, func_name, func_model):
        self.func_name = func_name
        self.func_model = func_model
        self.f = None  # f代表的文件对象.

        # 3. 重写 __enter__()函数, 表示: 上文
        def __enter__(self):
            print('这个是上文, 初始化属性的!')
            self.f = open(self.func_name, self.func_model, encoding='utf-8')
            return self.f

        # 定义read_data函数
        def read_data(self):
            for i in range(10):
                data = self.f.readline()
                print(data,end = '')

        # 4. 重写 __exit__()函数, 表示: 下文
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('这个是下文, 释放资源的!')
            self.f.close()


 # 5. 演示with open()语法, __enter__()返回的是: 文件对象
with Func('./1.txt', 'r') as f:
    # print('123')
    print(f.read())

yiled生成器

什么是生成器:

        根据程序员制定的规则循环生成数据,当条件不成立时则生成数据结束。数据不是一次性全

部生成出来,而是使用一个,再生成一个,可以节约大量的内存。

创建生成器的方式:

        ① 生成器推导式  ② yield 关键字

生成器推导式
# 创建生成器 
# 注意1:括号()代表 这是一个生成器,不是元组
# 注意2:括号()里面写的是数据的生成规则,返回一个对象,
                                # 对象内不是存的数据,而是产生数据的规则
my_generator = (i * 2 for i in range(5))   # 根据注意2
print(my_generator)

# next获取生成器下一个值
# value = next(my_generator)
# print(value)

# 遍历生成器
for value in my_generator:
    print(value)
yield生成器:

        只要在def函数里面看到有 yield 关键字那么就是生成器

"""
案例: 把给定的歌词文件(100条数据), 按照 8个1批次的形式, 分批包装到 生成其中, 并返回该生成器对象.

"""

# 1. 导包.
import math

# 2. 定义函数, 用于获取生成器, 即: 封装每批次的歌词.
def dataset_loader(batch_size):
    """
    自己编写的生成器代码, 用于将文件中的歌词数据, 分批次, 封装到: 生成器中.
    :param batch_size: 每批次, 多少条数据.
    :return: 无
    """
    # 2.1 读歌词文件.
    with open('./jaychou_lyrics.txt', 'r', encoding='utf-8') as f:
        lines = f.readlines()       # 列表,  [第1条, 第2条, 第3条......第100条]
    # 2.2 计算歌词的总条数.
    lyrics_count = len(lines)

    # 2.3 计算批次数量, 一共多少批.
    # ceil() 天花板数, 比这个数字大的所有整数中, 最小的那个整数, 例如: ceil(12.0) -> 12  ceil(12.1) -> 13, ceil(12.9) -> 13
    batch_count = math.ceil(lyrics_count / batch_size)  # 13批

    # 2.4 根据批次数量, 结合所有的歌词, 封装到 生成器中, 并返回.
    for idx in range(batch_count): # idx的值: 0, 1, 2, 3, 4, 5, 6..... 12, 包左不包右.
        # 第1批次: 去lines中获取: 0 ~ 8, 包左不包右.
        # 第2批次: 去lines中获取: 8 ~ 16, 包左不包右.
        # 第3批次: 去lines中获取: 16 ~ 24, 包左不包右.
        yield lines[idx * batch_size : idx * batch_size + batch_size]

if __name__ == '__main__':
    # 3. 调用函数
    my_loader = dataset_loader(8)       # 8条为一批.

    # 4. 遍历生成器, 获取到每批数据.
    # print(next(my_loader))  # 获取第 1 批
    # for data in next(my_loader):
    #     print(data, end='')
    #
    # print('-' * 31)
    # 第2批
    # for data in next(my_loader):
    #     print(data, end='')

    # 查看每一批
    for data in my_loader:
        print(data)

你可能感兴趣的:(python,开发语言)