Python进阶语法(一)with、math、yield、property

一、with语句

作用:自动释放资源,出现异常也能关闭;用来处理上下文管理器对象的

例题1、读取文件内容

f = open("./1.txt", 'r', encoding='utf-8')
print(f.read())
f.close()

上述代码存在的问题:1. 如果目标文件不存在,会报错

                                    2. 手动close()如果忘记的话,会比较浪费资源

解决方案1:如果目标文件不存在,会报错,捕获异常

try:
    # 尝试执行的代码
    f = open("./1.txt", 'r', encoding='utf-8')
    print(f.read())
except IOError as e:
    # 出问题后的解决方案, 文件不存在就创建
    f = open("./1.txt", 'w', encoding='utf-8')
finally:
    # 释放资源.
    f.close()

解决方案2:with open()写法

with open('1.txt', 'r',encoding='utf-8') as f:
    # 这里的内容执行完毕后, 会被自动释放资源.
    print(f.read())

可以明显看出,with 的写法更简便

2、上下文管理器

概述:一个类只要实现了__enter__()和__exit__(),则该类创建的对象就是上下文管理器

例题2:演示上下文管理器,解释 with open() 的原理

1. 自定义上下文管理器类
class MyFile:
    # 2. 重写 __init__()魔法方法, 初始化: file_name(文件名), file_model(文件模型)
    def __init__(self, file_name, file_model):
        """
        初始化属性的
        :param file_name:   文件名
        :param file_model:  文件(操作)模型, r:只读, w:只写, a:追加
        """
        self.file_name = file_name
        self.file_model = file_model
        self.fp = None      # fp代表的文件对象.

    # 3. 重写 __enter__()函数, 表示: 上文. 即: with语句执行前, 做的事儿
    def __enter__(self):
        print('这个是上文, 初始化属性的!')
        self.fp = open(self.file_name, self.file_model, encoding='utf-8')
        return self.fp    # fp就是文件对象.

        # return self     # 返回MyFile类的对象,走6

    # 4. 重写 __exit__()函数, 表示: 下文, 即: with语句执行完毕后, 做的事儿
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('这个是下文, 释放资源的!')
        self.fp.close()

# 5. 演示with open()语法, __enter__()返回的是: 文件对象
with MyFile('./1.txt', 'r') as fp:
    # 这里的内容执行完毕后, 会被自动释放资源
    print(fp.read())


# 6. 演示with open()语法, __enter__()返回的是: MyFile类的对象, 即: 上下文管理器类的对象
# with MyFile('./1.txt', 'r') as mf:
#     # 这里的内容执行完毕后, 会被自动释放资源.
#     print(mf.fp.read())
二、math包

ceil( ) 天花板数:获取比这个数字大的所有整数中,最小的那个整数

例如:ceil(12.0)  → 12

           ceil(12.1)  → 13

           ceil(12.9)  → 13

import math
math.ceil(i)    # 获取比i大的最小整数
三、生成器

1、作用:根据程序员写的规则,快速生成数据,降低能耗

2、写法:生成器对象  =(生成器规则)        # 小括号是生成器,不是元组的意思

例题:演示生成器写法

列表推导式:

my_list = [i for i in range(1, 6)]
print(my_list)      # [1, 2, 3, 4, 5]

集合推导式:

my_set = {i for i in range(1, 6)}
print(my_set)

生成器:

my_generator = (i for i in range(1, 6))
print(my_generator) # 直接打印, 打印的是 生成器对象的地址

发现打印的是生成器的地址,如何获取数据呢?

方式1:遍历

for i in my_generator:
    print(i)

方式2:使用 next( )调用1次,获取1个结果

print(next(my_generator))
print(next(my_generator))
print(next(my_generator))
print(next(my_generator))
print(next(my_generator))
四、yield  i

作用:将数据 i 封装到生成器中,自动返回生成器对象

# 1. 定义函数, 获取1 ~ 5之间所有的数据, 封装到生成器中, 并返回
def get_generator(n):
    """
    演示yield关键字, 它会将数据封装到生成器中, 并返回
    :param n: 要生成的数字的区间
    :return: 无
    """
    for i in range(1, n + 1):
        # 使用 yield关键字 把数据存储到生成器中 
        yield i   # yield作用: 把数字i封装到生成器中, 函数执行完毕后, 返回生成器对象

# 2. 调用 get_generator()函数, 获取生成器对象
g = get_generator(17)
print(g)        # 生成器对象
# 3. 从生成器中获取数据.
for i in g:
    print(i)
综合案例

需求:把给定的文件(100条数据)按照每批次8条的形式,分批包装到 生成器中,并返回该生成

           器对象

# 1. 导包.
import math

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

    # 2.3 计算一共多少批
    batch_count = math.ceil(count / batch_size)  

    # 2.4 根据批次数量, 封装到 生成器中, 并返回
    for idx in range(batch_count):
        yield lines[idx * batch_size : idx * batch_size + batch_size]

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

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

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

1、作用:把方法当属性使用,可以简化代码

2、用法:

        1. 充当装饰器
        @property                修饰获取值的方法
        @属性名.setter         修饰设置值的方法,属性名要和@property修饰的函数名保持一致

        2. 可以修饰类变量
        类属性名 = property(get_方法名,set_方法名)

3、例子:

充当装饰器的用法:

# 1. 定义Person类, 有1个私有属性age, 尝试在外访问 私有的age变量
class Person:
    # 初始化1个私有的 变量 age
    def __init__(self) -> None:
        self.__age = 20     # 私有的 对象属性

    # 为了让外界访问 类中私有内容, 我们可以提供公共的访问方式
    # 不使用装饰器
    # def get_age(self):
    #     return self.__age
    #
    # def set_age(self, age):
    #     self.__age = age

    # 使用装饰器
    @property
    def age(self):
        return self.__age

    @age.setter      # @property修饰的函数名.setter
    def age(self, age):
        self.__age = age

if __name__ == '__main__':
    # 不使用装饰器
    # 2 创建Person类的对象, 尝试调用 age属性
    # p = Person()
    # 访问变量
    # print(p.get_age())  # 20
    # 修改变量
    # p.set_age(30)
    # 访问变量
    # print(p.get_age())  # 30

    # 使用装饰器
    # 2. 创建Person类的对象, 尝试调用 age属性
    p = Person()
    # 访问变量
    print(p.age)  # 20
    # 修改变量
    p.age = 30
    # 访问变量
    print(p.age)  # 30

修饰类变量用法:

# 1. 定义Person类, 有1个私有属性age, 尝试在外接访问 私有的age变量
class Person:
    # 初始化1个私有的 变量 age
    def __init__(self) -> None:
        self.__age = 20     # 私有的 对象属性

    # 修饰之后, 就可以在外界把age当做类属性来使用了
    age = property(get_age, set_age)      # 类属性

if __name__ == '__main__':
    # 类属性的用法
    p = Person()
    print(p.age)    # 获取值
    p.age = 30      # 设置值
    print(p.age)    # 获取值

 恭喜你!任务完成,要多多练习哟~

  • 12
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值