一些实用的高阶用法--python

1、上下文管理器

(一)、with...open...

复制代码
with.open()格式:
    with open(文件名, 模式, 码表) as 文件对象名:
        正常的读写操作即可.
    特点:
        会在with.open()里边的代码执行完后后, 自动释放资源.

实际上,with.open()它就是上下文管理器对象

python 复制代码
with open('./1.txt', 'r', encoding='utf-8') as src_f:
    data = src_f.read()
    print(f'读取到: {data}')

(二)上下文管理器

概述

复制代码
一个类只要实现了__enter__()和__exit__()方法,那么这个类就是一个上下文管理器类.
该类的对象 = 上下文管理器对象.

特点

  • 上下文管理器对象, 可以结合with语句使用.
  • 在with语句执行前, 会自动调用__ enter __()方法, 用于初始化某些 变量.
  • 在with语句执行后, 会自动调用__ exit __()方法, 用于清理某些资源, 即使前边有Bug也会调用该方法.

例如--返回类的属性(文件对象)

python 复制代码
# 1. 定义1个上下文管理器类, 表示: 我们自己的处理文件的操作.
class MyFile:
    # 2. 在 init魔法方法中, 初始化: 属性信息.
    def __init__(self, file_name, mode):
        # 文件名(文件路径)
        self.file_name = file_name
        # 模式, r, w...
        self.mode = mode
        # 文件对象
        self.file_obj = None

    # 3. 在enter魔法方法中, 获取1个: 文件对象, 用于读写文件操作.
    def __enter__(self):
        print('我是 enter 魔法方法')
        # 获取文件对象
        self.file_obj = open(self.file_name, self.mode, encoding='utf-8')
        # 返回文件对象.
        return self.file_obj    # file_obj = open()对象

    # 4. 在exit魔法方法中, 关闭文件对象.
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.file_obj.close()
        print('文件对象已被关闭...')

# 5. 在main方法中, 测试自定义的 文件对象.
if __name__ == '__main__':
    # 如果 enter魔法方法返回的是: open()对象, 代码如下
    with MyFile('./1.txt', 'r') as file_obj:
        # print( 10 / 0)    # 即使有Bug, 也会尝试关闭资源.
        data = file_obj.read()
        print(f'读取到: {data}')

例如--返回类对象

python 复制代码
# 1. 定义1个上下文管理器类, 表示: 我们自己的处理文件的操作.
class MyFile:
    # 2. 在 init魔法方法中, 初始化: 属性信息.
    def __init__(self, file_name, mode):
        # 文件名(文件路径)
        self.file_name = file_name
        # 模式, r, w...
        self.mode = mode
        # 文件对象
        self.file_obj = None

    # 3. 在enter魔法方法中, 获取1个: 文件对象, 用于读写文件操作.
    def __enter__(self):
        print('我是 enter 魔法方法')
        # 获取文件对象
        self.file_obj = open(self.file_name, self.mode, encoding='utf-8')
        # 返回文件对象.
        return self           # self = MyFile的对象

    # 4. 在exit魔法方法中, 关闭文件对象.
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.file_obj.close()
        print('文件对象已被关闭...')

# 5. 在main方法中, 测试自定义的 文件对象.
if __name__ == '__main__':
    # 如果 enter魔法方法返回的是: MyFile对象, 代码如下.
    with MyFile('./1.txt', 'r') as mf:
        # print( 10 / 0)    # 即使有Bug, 也会尝试关闭资源.
        data = mf.file_obj.read()
        print(f'读取到: {data}')

(三)、总结

在__ enter __这个魔法方法,可以选择返回类对象,也可以选择返回类属性,这个只影响后续读取文件的写法格式。

2、生成器

(一)、简介

概述

生成器指的是 Generator对象, 它不再是像以往一样, 一次性生成所有的数据. 而是用一个, 再生产一个.

基于用户写的规则(条件)来生成数据, 如果条件不成立, 则生成结束.

目的

节约内存资源, 减少内存占用.

实现方法

  • 推导式写法
  • yield关键字实现

迭代

迭代指的是: 逐个的从容器类型中获取每一个元素的过程, 称之为: 迭代(遍历)

例如: 列表, 集合, 字典, 生成器等, 都是可以遍历(迭代)的, 所以它们也称之为: 可迭代对象

从生成器中获取数据

  • next()函数
  • 遍历

(二)、推导式写法

python 复制代码
# 案例: 演示推导式写法, 获取生成器对象.
if __name__ == '__main__':
    # 1. 回顾: 列表推导式.
    list1 = [i for i in range(1, 6)]
    print(f'list1: {list1}')             # [1, 2, 3, 4, 5]
    print(f'list1的类型: {type(list1)}')  # <class 'list'>

    # 2. 回顾: 字典推导式.
    dict1 = {i: i ** 2 for i in range(1, 6)}
    print(f'dict1: {dict1}')
    print(f'dict1的类型: {type(dict1)}')  # <class 'dict'>

    # 3. 回顾: 集合推导式.
    set1 = {i for i in range(1, 6)}
    print(f'set1: {set1}')
    print(f'set1的类型: {type(set1)}')    # <class 'set'>
    print('-' * 21)

    # 4. 尝试写1个"元组推导式", 注意: 没有元组推导式这个说法, 它的底层是: 生成器对象.
    # 生成器写法1: 推导式写法.
    my_generator = (i for i in range(1, 6))
    print(f'my_generator: {my_generator}')            # 地址值
    print(f'my_generator的类型: {type(my_generator)}') # <class 'generator'>
    print('-' * 21)

    # 5. 生成器不是一下子生成所有的数据, 而是用一个再生成1个.
    # 问: 如何从生成器中获取数据呢?
    # 答: 1: next()函数.   2.for循环遍历.
    # 方式1: next()函数, 从生成器中获取数据.
    print(next(my_generator))
    print(next(my_generator))
    print(next(my_generator))
    print(next(my_generator))
    print(next(my_generator))
    # print(next(my_generator))   # 报错: StopIteration, 停止迭代
    print('-' * 21)

    # 方式2: for循环遍历, 获取生成器的数据
    # 细节: next()是移动指针的, 获取下个元素, 如果不注释上边的代码, 这里打印结果是 空.
    for i in my_generator:
        print(i)

(三)、yield写法

python 复制代码
# 需求: 获取 1 ~ 10之间的整数, 生成器写法.
# 1. 定义函数, 获取: 生成器对象.
def get_generator():
    # 回顾: list写法
    # list_data = []
    # for i in range(1, 11):
    #     list_data.append(i)
    # return list_data      # 返回列表对象

    # 对比: yield写法, 效果类似于上边的代码, 只不过返回的是: 生成器对象.
    for i in range(1, 11):
        yield i   # yield的作用: 1.创建生成器对象.  2.逐个的把每个元素放到生成器对象中.  3.函数结束时, 返回生成器对象.


# 2. 测试上述的函数.
if __name__ == '__main__':
    # 3. 调用函数, 获取生成器对象.
    my_generator = get_generator()
    print(type(my_generator))       # <class 'generator'>

    # 4. 从生成器对象中, 获取数据.
    # 方式1: next()函数
    print(next(my_generator))   # 1
    print(next(my_generator))   # 2
    print(next(my_generator))   # 3
    print('-' * 21)

    # 方式2: 遍历.
    for i in my_generator:
        print(i)

需求

python 复制代码
import math
# 案例1: 定义函数 dataset_loader(batch_size), 用于获取: 批次数据.
def dataset_loader(batch_size):
    """
    自定义的函数, 获取批次数据的.
    :param batch_size: 每批次数据的条数.
    :return: 生成器对象, 每个数据 = 1批的数据
    """
    # 1. 读取源文件, 获取到所有的数据.
    with open('./data/jaychou_lyrics.txt', 'r', encoding='utf-8') as src_f:
        # 一次性读取所有的行, 并放到列表中.
        list_data = src_f.readlines()  # 数据格式: ['第1行\n', '第2行\n', '第3行\n'...]
    # 2. 获取数据的总条数.
    line_count = len(list_data)
    # 3. 根据数据的总条数, 结合每批次的数据条数, 计算: 总批次数.
    batch_count = math.ceil(line_count / batch_size)
    # 4. 遍历 总批次数, 获取到: 每个批次的 编号, 然后生成: 该批次的数据.
    for batch_idx in range(batch_count):
        """
        推理过程:
            假设 batch_size = 8, batch_count = 13, 即: 13批, 8条/批, 则:
            batch_idx = 0, 代表第1批数据, 数据为: 第1条 ~ 第8条, 索引为: [0:8]
            batch_idx = 1, 代表第2批数据, 数据为: 第9条 ~ 第16条, 索引为: [8:16]
            batch_idx = 2, 代表第3批数据, 数据为: 第17条 ~ 第24条, 索引为: [16:24]
            ......
        """
        yield list_data[batch_idx * batch_size: batch_idx * batch_size + batch_size]


# 在main函数中测试.
if __name__ == '__main__':
    # 5. 获取生成器对象.
    data_loader = dataset_loader(batch_size=8)
    # 6. 获取第1批次的数据.
    # print(next(data_loader))
    batch_data1 = next(data_loader)
    # 具体的获取第1批次中每条数据的过程.
    for line in batch_data1:
        print(line, end='')
    print('-' * 21)

    # 7. 获取第2批次的数据.
    print(next(data_loader))

3、property

(一)、简介

概述

用来装饰函数,装饰后,可以把函数当做变量来用.

目的

简化开发,提高效率

用法

  • 充当装饰器用
  • 修饰类变量

(二)、用做装饰器

用法

复制代码
1. 在 获取值的函数上, 加上 @property
2. 在 设置值的函数上, 加上 @方法名.setter, 注意: 这里的方法名是 @property修饰的方法名
3. 之后就可以把 函数 当做 变量来直接使用了.

例如

python 复制代码
# 需求: 定义学生类, 有个私有的属性name, 提供公共的访问方式, 并测试.
# 1. 定义学生类.
class Student:
    # 2. 私有属性.
    def __init__(self):
        self.__name = '张三'      # 私有属性.

    # 3. 获取值的方法.
    # @property
    # def get_name(self):
    #     return self.__name
    #
    # # 4. 设置值的方法.
    # @get_name.setter
    # def set_name(self, name):
    #     self.__name = name

    # 5. get_xxx(), set_xxx()函数 如果结合 property装饰器用, 具体写法如下:
    # 获取值的方法
    @property
    def name(self):
        return self.__name

    # 设置值的方法.
    @name.setter
    def name(self, name):
        # 根据需求, 可以对传入的值做校验.
        # if name == '段誉':
        #     print('名字不能为段誉')
        # else:
        #     self.__name = name

        # 直接赋值.
        self.__name = name

# 在main中测试.
if __name__ == '__main__':
    # 6. 创建学生对象.
    s = Student()

    # 7. 访问Student类的私有属性name
    # print(s.name)       # 报错
    # print(s.__name)     # 报错.
    # s.set_name('乔峰')
    # print(s.get_name())

    # 8. 访问Student类的私有属性name
    # s.set_name = '虚竹'
    # print(s.get_name)

    # 看起来调用的是"属性", 其实底层是: 函数.
    s.name = '段誉'
    print(s.name)

(三)、类属性

用法

复制代码
1. 直接在类中编写 类变量名 = property(获取值的方法名, 设置值的方法名)
2. 之后就可以通过 类名.类变量名的方式 来使用了, 这个是充当: 类变量的.
3. 如果要精准的修改或者获取某个学生的信息, 可以通过 对象名.属性名的方式调用.

例如

python 复制代码
# 需求: 定义学生类, 有个私有的属性name, 提供公共的访问方式, 并测试.
# 1. 定义学生类.
class Student:
    # 2. 私有属性.
    def __init__(self):
        self.__name = '张三'      # 私有属性.

    # 3. 获取值的方法.
    def get_name(self):
        return self.__name

    # 4. 设置值的方法.
    def set_name(self, name):
        self.__name = name

    # 5. property充当类属性的用法.
    # 参1: 获取值的函数.
    # 参2: 设置值的函数.
    # 注意: 顺序不要写反了, 这个是固定的顺序, 写反了会报错.
    name = property(get_name, set_name)


# 在main中测试.
if __name__ == '__main__':
    # 6. 创建学生对象.
    s = Student()
    s.name = '乔峰'         # 对象属性
    # Student.name = '乔峰' # 类属性
    print(s.name)
    print('-' * 21)

    # 7. 再次创建学生对象.
    s2 = Student()
    print(s2.name)

4、迭代器

(一)、简介

概述

类中只要实现了__ next __ ()和 __ iter __ (),它就是迭代器类。

作用

逐个遍历,获取元素值,目的是减少内存的占用。

用一个拿一个,一般结合生成器对象使用。

(二)、实现

python 复制代码
class MyIterator():
    # 给一个默认的限制值
    def __init__(self, limit):
        self.limit = limit
        self.current = 0
    
    # 重写__next__()函数
    def __next__(self):
        if self.current >= self.limit:
            # 抛出异常,终止程序
            raise StopIteration
        # 计数
        self.current += 1
        # 返回当前计数
        return self.current

    def __iter__(self):
        # 返回对象本身
        return self

if __name__ == '__main__':
    my_iter = MyIterator(5)
    print(type(my_iter)) # <class '__main__.MyIterator'>
    for i in my_iter:
        print(i)
    # 如果再读取就会触发上面的异常
    # print(next(my_iter))

5、json字符串处理

(一)、简介

概述

JS的对象表示法,轻量级的数据交互格式。

作用

比较适合人们的阅读和编写,也比较适合计算机的识别和编译。

格式

复制代码
'{"键名": "值", "键名": "值"}'

使用步骤

python 复制代码
# 导包
import json
# 解析
# Json字符串 => Json对象
loads()
# 格式化
# Json对象 => Json字符串
dumps()

(二)、实现

解析

python 复制代码
# 解析
json_str = '{"name": "乔峰", "age": 39, "kongfu": "降龙十八掌"}'
print(type(json_str))  # <class 'str'>

# 方式一
# json_obj = json.loads(json_str)
# print(type(json_obj))  # <class 'dict'>
# print(json_obj)        # {'name': '乔峰', 'age': 39, 'kongfu': '降龙十八掌'}

# 方式二
json_obj = eval(json_str)
print(type(json_obj))    # <class 'dict'>

格式化

python 复制代码
# 格式化
# dumps默认用ascii码表解析,默认是True
# json_str = json.dumps(json_obj)  # {"name": "\u4e54\u5cf0", "age": 39, "kongfu": "\u964d\u9f99\u5341\u516b\u638c"}
json_str = json.dumps(json_obj, ensure_ascii=False)  #{"name": "乔峰", "age": 39, "kongfu": "降龙十八掌"}
print(json_str)
相关推荐
databook1 小时前
Manim实现闪光轨迹特效
后端·python·动效
Juchecar2 小时前
解惑:NumPy 中 ndarray.ndim 到底是什么?
python
用户8356290780512 小时前
Python 删除 Excel 工作表中的空白行列
后端·python
Json_3 小时前
使用python-fastApi框架开发一个学校宿舍管理系统-前后端分离项目
后端·python·fastapi
数据智能老司机9 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机10 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机10 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机10 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
c8i10 小时前
drf初步梳理
python·django
每日AI新事件10 小时前
python的异步函数
python