python答辩复习

python基础知识

基础

  1. Python 依靠什么区分代码块?缩进规范是什么?缩进错误会怎样?
    Python 依靠缩进区分代码块,不使用 {};规范推荐 4 个空格,也可用 1 个制表符;同一层级代码缩进量必须一致;缩进不一致会直接抛出缩进语法错误,程序无法运行。
  2. 基础类型(内置类型)
    整数(int)、浮点数(float)、布尔值(bool)、字符串(str)、字节串(bytes)、空值(NoneType)
  3. 引用类型(复合类型)
    列表(list)、元组(tuple)、字典(dict)、集合(set)、枚举类型(Enum)、自定义类(class)
  4. 变量基本类型
    数字、字符串、列表、元组、集合、字典
  5. 变量保存的数据,有哪些类型的数据?
    数字、布尔数据、字符串、None、列表、元组、字典、集合、函数、类、对象
  6. 变量的存值与取值
    存值:a=10,变量不存在,在当前作用域创建,赋值初始化;变量存在则更新赋值
    取值:取最近的一次
    总结:变量存值,有就更新,没有就创建;变量取值,没有就报错,有就取出变量最近一次存的值
  7. 变量名、标识符
    字母、数字、下划线,不能以数字开头
    大小驼峰:agent_name、agentName、AgentName
    不能使用Python的关键字作为标识符的名称
    要区分大小写
  8. 变量的三个基本属性
    id号:反映的是变量值的内存地址使用id()函数查看
    类型:每一个变量都有自己的类型。
    值:存储的数据。
  9. 变量的赋值与地址变化
    a在创建时,被绑定到整数对象10(对于小整数,指向全局缓存池)。
    创建b时,Python将b绑定到a所绑定的同一个对象上。
    此时ab是两个独立的变量标签,但它们指向同一块内存地址
  10. 引用
    变量名绑定到对象的地址,变量本身不存数据,只存对象地址。
    赋值就是「新建引用」,不是复制对象
  11. 可变和不可变
    不可变对象:int、float、str、tuple -- 对象创建后值不能修改,一旦修改,会创建新对象,旧引用不变。
    可变对象:list、dict、set -- 对象本身能原地修改,所有指向它的引用全部同步变化
  12. 深浅拷贝(解决多引用共用对象问题)
    当不想多个变量共用同一个可变对象时,使用拷贝生成新对象:
    浅拷贝 :copy.copy () / 切片 [:] /list (),只拷贝第一层对象,内部嵌套元素依然共用引用
    深拷贝 : copy.deepcopy (),递归拷贝所有层级,完全独立,没有共享引用
  13. 引用计数(垃圾回收底层原理)
    每个对象自带一个引用计数器:记录当前有多少变量引用这个对象
    计数 + 1 场景:对象赋值给变量 a = [1,2]、作为参数传入函数 func(a)、放入容器 lst = [a]
    计数 - 1 场景:变量重新赋值 a = 100、变量删除 del a、函数执行结束,局部变量销毁、容器被销毁
    垃圾回收:当引用计数变为 0,Python 自动释放这块内存
  14. 函数传参:传递的是引用(值传递不存在)
    Python 参数传递统一是引用传递(传对象地址)
    传不可变对象:函数内修改只会新建对象,外部变量不变
    传可变对象:函数内原地修改,外部同步变化
  15. del 关键字:删除引用,不是删除对象
    del 变量名:只是切断变量和对象的绑定,对象引用计数 - 1;
    只有计数为 0,对象才会被销毁。
  16. 注释
    单行:#,快捷键Ctrl + /
    多行:"""xxxx"""'''xxx'''
  17. 三单、三双引号能混用吗?
    单双引号不能混合使用,否则语法报错。
  18. 关键字
    Python解释器提前占用了的标识符,每一个关键字都有自己的特殊功能,比如常用的if、for、while、import、def等等。
    可以通过调用Python的keyWord库来查看Python中的关键字都有哪些。
  19. 输出
    基本输出、格式化输出(%)、formatl方法、f-string
    formatl -- {:[填充][对齐][符号][宽度][,][.精度][类型]}
    格式化 -- m.n,m是用来控制输出数据的所占长度,n是用来控制输出数据的精度问题
  20. 可迭代对象
    字符串、列表、元组、range、字节串、字节数组、集合、不可变集合、字典、文件/io对象、迭代器/生成器、自定义可迭代
  21. 不可迭代
    整数 int、浮点数 float、布尔值 boolNone 都不能迭代,直接 for 循环会报错

基本类型

数字

  1. 数字的类型
    整数、小数、复数、布尔
    整数(int8 int16 int32 int64 uint8)
    小数(float32 float64)

  2. 进制
    数字更长用的划分:int8 int16 int32 int64 uint8 float32 float64
    二进制:逢二进一,以0b或0B开头,只有0和1两个数,计算机的世界就是由0和1组成的,通常8位为一组,比如0b11011001。
    八进制:逢八进一,以0o或0O开头,有0-7共8个数。
    十进制:逢十进一,有0-9共10个数。
    十六进制:逢十六进一,以0x或0X开头,包含0-9共10个数字以及A、B、C、D、E、F六个字母(字母大小写均可),通常为2位一组,比如0x1a
    开头全是数字0

  3. 二进制、八进制、十六进制数字开头标识是什么?对应转换函数?

    二进制0b/0B、八进制0o/0O、十六进制0x/0X
    转换函数:bin () 转二进制、oct () 转八进制、hex () 转十六进制。

    print(int(20.5))	# 20
    print(float(20))	# 20.0
    print(bin(3))	# 0b11
    print(oct(20))	# 0o24
    print(hex(29))	# 0x1d
    print(complex(29))	# (29+0j)
    print(complex(10,3))	# (10+3j)
    
  4. 源码、反码、补码
    对于正数:
    原码 = 反码 = 补码 = 二进制数
    对于负数:
    原码 = 二进制数
    反码 = 原码符号位不变,其他位按位取反(0变1,1变0)
    补码 = 反码 + 1

  5. 运算符分为哪几类
    算数、位、比较、逻辑、赋值

  6. 运算符的优先级
    运算符的优先级(从上向下排列,上面的优先级最高)
    速记口诀:幂乘除加减,移位与异或,比较,非与或,赋值放最后

    圆括号():圆括号内的表达式拥有最高优先级

    **:乘方运算

    *、/、%、//:算术运算符,先乘除

    +、-:算术运算符,后加减

    <<、>>:位运算符的左移与右移

    &:位运算符的按位与

    ^:位运算符的按位异或

    |:位运算符的按位或

    >、<、>=、<=、==、!=:比较运算符

    not、and、or:逻辑运算符

    =、+=等赋值运算符优先级最低

  7. 数学函数
    引入模块:import math
    绝对值:abs(x)
    上入整数:math.ceil(x)
    下舍整数:math.floor(x)
    四舍六入:round(x ,n) -- 5看齐,奇进偶不进
    最大最小:max(x1, x2,...)min(x1, x2,...)
    平方根:math.sqrt(x)
    x**y:math.pow(x, y)
    以10为基数的x的对数:math.log10(x)
    以 e*e*为底,计算的是自然对数:math.log(x) -- (自然常数,约等于 2.71828)

  8. 随机数
    引入:import random
    [0,1)范围内:random.random()
    指定范围内:random.randrange (start, stop,step)
    从序列的元素中随机挑选一个元素:random.choice(seq)

  9. 三角函数
    引入:import math
    弧度转角度:math.degrees(x)
    角度转弧度:math.radians(x)

字符串

  1. 字符串表达式
    引号引起来的单引号、双引号、三引号(三个三引号或双引号)
  2. 类型检测
    字符串用type函数检测的结果为str
  3. 转义字符
    \r 回车 \n 换行 \t 缩进 \\ 表示
    字符串前加r表示原始字符串:所见即所得,不转义
  4. 连接字符、输出字符
    +f-string*、索引、切片、.format()
  5. API
    居中--center(width, fillchar)
    计数--count(str, beg= 0,end=len(string))
    字符串是否以 suffix 结束--endswith(suffix, beg=0, end=len(string))
    检测 str 是否包含在字符串中--find(str, beg=0, end=len(string))
    用下标查找--index(str, beg=0, end=len(string))
    以指定字符串作为分隔符--join(seq)
    字符串长度--len(string)
    大写转小写--lower()
    小写转大写--upper()
    小转大,大转小--swapcase()
    第一个字符转换为大写--capitalize()
    所有单词都是以大写开始--title()
    删除字符串左右两边的空格--strip(chars)
    以 sep为分隔符截取字符串--split(sep="", maxsplit=string.count(str))
    将字符串中的 old 替换成 new--replace(old, new , max)

列表

  1. 切片
    切片是浅拷贝操作,[含:不含:步长]
  2. 修改、更新(添加)
    list[2]=5;append()
  3. 删除元素
    del list[2]
  4. 操作符/运算符--列表、元组
    len()、+*、in、for _ in [1,2,3]
  5. API
    len()、max()、min()、list()
  6. 方法
    append、count、extend、index、insert、pop、remove、reverse、sort、clear、copy
  7. 引用数据的思想:
    列表是一个引用数据:它会创建列表对象,占用内存空间
    x = [10,20,30,40] -- 创建了一个列表对象,占用了一个内存空间
    y = x -- 不会重新创建一个列表对象,也就是说不会新开辟内存空间
    y[1] = 666
    print(x) -- [10,666,30,40]

元组

  1. 元组不可变(不可修改),可以有不同类型的数据,但如果嵌套可变数据,该可变数据可以修改
  2. 解构赋值:
    等号左侧只有一个变量右侧多个数据用逗号分隔(无外层容器) 时,Python 会自动将右侧整体封装为元组再赋值
    按照索引顺序,依次赋值给等号左边的变量(一次多个变量的语法)
  3. 元组中只包含一个元素时,需要在元素后面添加逗号 ,否则括号会被当作运算符使用
  4. 对元组进行连接组合:+
  5. 元组元素不可单个删除,但可以用del删除整个元组
  6. API:
    len()、max()、min()、tuple()

字典

  1. 键必须是唯一的,但值则不必;值可以取任何数据类型,但键必须是不可变的,如字符串,数字
  2. 访问
    dic[key]--没有会报错
    dict.get(key, default=None)--返回值,没有返回默认值
    dict.items()--以列表返回一个视图对象 -- dict_items([('Name', 'hqyj'), ('Age', 8), ('Class', 'First')])
    dict.keys()--返回一个视图对象
    dict.values()--返回一个视图对象
  3. 修改
    mydic = {'Name': 'hqyj', 'Age': 7, 'Class': 'First'} 
    mydic['Age'] = 8 # 更新
    mydic['School'] = "华清" #添加信息```
    
  4. 删除
    del mydic['Name'] # 删除键 'Name'
    mydic.clear()     # 清空字典
    del mydic         # 删除字典```
    
  5. 特性
    不允许同一个键出现两次。创建时如果同一个键被赋值两次,后一个值会被记住
    键必须不可变,所以可以用数字,字符串或元组充当,而用列表就不行
  6. API
    len()、srt()、type()
  7. 方法
    clear、copy、get、key in dict、setdefault、update、pop、popitem()
    返回视图:items、key、values

集合

  1. 无序的不重复元素序列,可以进行交集&、并集|、差集-等常见的集合操作
  2. 使用大括号 { } 创建集合,元素之间用逗号 , 分隔, 或者也可以使用 set() 函数创建集合
  3. 创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典
  4. 添加
    s.add(x):添加元素到集合
    s.update(x):添加元素到集合,且参数可以是列表,元组,字典等,x 可以有多个,用逗号分开
  5. 移除
    s.remove(x):将元素 x 从集合 s 中移除,如果元素不存在,则会发生错误。
    s.discard(x):将元素 x 从集合 s 中移除,如果元素不存在,不会发生错误。
    s.pop():对集合进行无序的排列,然后将这个无序排列集合的左面第一个元素进行删除。
  6. API
    len、clear、x in s、add、clear、copy、discard、pop、remove、update
    交:intersection()、intersection_update()
    并:union()、
    差:difference()、difference_update()、
    判断:isdisjoint()、issubset()、issuperset()
    不重复(A+B-AB):symmetric_difference()
    ((A-B)+(B-A)):symmetric_difference_update()

条件、循环

  1. range
    生成一个整数序列,序列中的每个元素按照指定的步长递增
    并不会真正创建一个列表,而是返回一个可迭代的对象——range对象
  2. for
    迭代遍历可迭代对象(如列表、字符串、字典等)
  3. while
    条件为真时重复执行代码块
  4. 循环控制
    break:用于跳出当前循环;continue:用于跳过当前迭代,继续下一次迭代。
  5. pass
    占位符

python高级技巧

推导式

  1. enumerate():全局函数,获取序列的索引和元素

  2. iffor 后面:作为过滤条件,满足则保留元素,不满足则丢弃(不需要 else

  3. iffor 前面(即冒号后面的值表达式):作为三元条件表达式,必须带 else,含义是:

    • 条件满足 → 返回 if 前面的值

    • 条件不满足 → 返回 else 后面的值

列表推导式

  1. 语法(基本格式)
    [表达式 for 变量 in 序列]
    [表达式 for 变量 in 序列 if 条件]
    [表达式 for 变量1 in 容器1 for 变量2 in 容器2(可以是变量1)]

字典推导式

  1. 基本格式
    { key_expr: value_expr for value in collection }
    { key_expr: value_expr for value in collection if condition }

集合推导式

  1. 基本格式
    { expression for item in Sequence }
    { expression for item in Sequence if conditional }

元组推导式

  1. 基本格式
    (expression for item in Sequence )
    (expression for item in Sequence if conditional )

生成器表达式

  1. 语法
    (表达式 for 变量 in 序列 if 条件)
    使用圆括号,返回生成器对象,节省内存
  2. 使用next()获取值
  3. 按需生成,不占用大量内存

函数

定义、参数

  1. 调用函数代码运行后,才会把函数中的代码运行一遍,而且相互独立
    函数调用一次,就会重新运行一次;函数不调用,函数中的代码就不会执行
  2. 文档字符串:三引号(""" / ''')写在函数、类、文件最开头的注释文本,属于字符串对象,专门用来描述功能、参数、返回值,区别于普通单行注释#
  3. return [表达式] 结束函数,选择性地返回一个值给调用方,不带表达式的 return 相当于返回 None
    函数 return 多个值时,用逗号分隔,Python 自动打包成元组返回
  4. 参数类型
    必需参数、默认参数(形参)、可变参数、关键字参数(实参)
  5. 参数位置
    必须按先后顺序:位置参数、关键字参数、*修饰符参数(剩余位置参数--元组)、**修饰符参数(剩余关键字参数--字典)
    *占位的参数(后面:关键字参数)、/占位的参数(前面:位置参数)
    默认值参数:必须放在没有默认值参数的后面
  6. 形参和实参
    函数调用时形参变量不能多次赋值,但是执行时可以
    函数调用时,形参变量必须有值(1.传入 2.默认值)
    传入的数据不允许超过形参变量的数量
    调用函数传入的数据叫实际传入的参数,称之为实参
  7. 可变数据类型:列表、字典、集合、函数、类、实例对象、bytearray字节数组;
    其余基础类型(数字、布尔、复数、字符串、元组、None、bytes字节串)均为不可变类型。
  8. 不可变类型(值传递): 如整数、字符串、元组。
    可变类型(引用传递): 如 列表,字典。
    python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。
  9. yeild关键字
    函数内部yeild关键字 会让函数产生生成器对象数据
  10. 匿名函数 - lamda函数
    函数定义时没有名字时使用
    语法:lambda arguments: expression
    冒号前面是形参的变量名,冒号后面是函数内部要执行的代码,代码结果为函数返回值

作用域

  1. 函数的作用域
    一个变量和一个函数在哪些地方可以被访问使用,那些地方就是他们起作用的代码区域,也叫作用域
  2. 函数内部写代码可以使用函数内部的变量和函数,也可以使用函数外部的变量和函数
    函数外部写代码可以使用函数外部的变量和函数,不能使用函数内部的变量和函数
  3. 作用域最难的一句总结:
    函数在A作用域定义 在B作用域中调用 运行代码是在它定义的地方(A作用域)
  4. 局部变量和全局变量
    如果在函数内部,操作变量给它存值,希望操作的变量时外部的变量,只能使用两个关键字 globalnonlocal
    global:在函数内部提前声明,该变量无论取值还是存值,都是全局变量
    nonlocal:在嵌套函数内部提前声明,该变量不是当前作用域的变量,无论取值还是存值,都只操作上层变量,上层没有就操作上层的上层,直到全局都没有就报错(不会操作全局变量)
  5. LEGB 查询顺序是什么?举例子说明
    查找变量顺序:局部 L → 外层嵌套 E → 全局 G → 内置 B。
    先从当前函数内部找,找不到一层层向外,最后找系统内置名称,全部找不到报错。
  6. 函数调用结束后,局部变量还存在吗?
    普通函数执行完毕,局部作用域销毁,局部变量回收,无法外部访问;只有闭包会保留外层函数变量环境。
  7. 什么是闭包?闭包和作用域的关系?
    闭包:嵌套内部函数,引用了外层函数的局部变量,外层函数执行结束后,外层变量不会被销毁。
    原理:内部函数保存了外层作用域环境,延长局部变量生命周期。
  8. 函数内只要出现 变量=值 赋值,无论在什么位置,该变量在定义函数的时候就会直接被判定为局部变量

闭包、自调用、重复调用

  1. 什么是闭包?满足 3 个条件就是闭包
    存在嵌套函数(内层函数、外层函数)
    内层函数引用外层函数的局部变量(非全局变量)
    外层函数返回内层函数对象
  2. 普通函数执行完,局部变量直接销毁;
    闭包会保存外层函数作用域、变量引用,外层函数执行结束,变量不会回收,内层函数持续使用。
  3. nonlocal 和闭包
    内层想要修改外层变量,必须加nonlocal,否则判定为局部变量报错
  4. 闭包优点
    封装私有数据,外部无法直接修改外层变量
    延长变量生命周期,不用全局变量
  5. 闭包缺点
    变量长期占用内存,不手动释放会造成内存浪费
    结构复杂,可读性下降
  6. 闭包是嵌套内层函数引用外层局部变量,外层返回内层函数;可保存外层作用域数据,修改外层变量需要 nonlocal 关键字
  7. 什么是回调函数?
    函数 A 当作参数传递给另一个函数 B,在 B 内部自动调用 A,A 就是回调函数
  8. 回调函数常用场景
    sorted 的 key 参数(lambda 回调)
    定时器、异步任务、GUI 按钮点击事件
    数据处理、接口请求成功 / 失败回调
  9. 匿名函数 lambda 常用作简易回调
    简短逻辑不需要单独定义函数,直接传 lambda
  10. 区分:回调 vs 普通函数调用
    普通调用:代码主动写func()
    回调:函数由其他函数内部自动触发执行
  11. 普通函数重复调用:每次全新局部作用域
    每次调用函数都会开辟独立局部空间,上次调用的局部变量全部销毁,互不干扰。
  12. 闭包重复调用:会保留状态(记忆上次数据)
    多次调用同一个闭包实例,变量持续累加;如果重新创建新闭包,会重置数据
  13. 递归调用(特殊重复调用)
    函数自己调用自己,必须设置终止条件,否则无限递归报错
    缺点:递归深度有限,大量重复调用容易栈溢出
  14. 重复调用带来的性能问题
    普通函数:每次执行都要重新创建局部变量、重复计算,效率低
    解决方案:缓存(装饰器 lru_cache),相同参数重复调用直接读取缓存结果,不用重复计算
  15. 全局变量实现调用计数(不推荐,对比闭包)
    缺点:全局变量污染,多函数共用容易冲突,优先使用闭包

引用

  1. 核心概念:变量是引用标签,数据在内存
  2. 核心名词
    数据(对象):内存中真实存在的值,有独立 id(内存地址),分可变 / 不可变。
    数字、字符串、列表、字典都叫对象。
    变量(引用标签):变量不是盒子,只是贴在对象上的标签 / 引用
    a = 10:在内存创建整数对象10,把标签a贴到这个对象上
  3. 赋值本质:修改引用绑定
  4. 基础数据类型:不可变对象的引用规则
    不可变类型:int float bool str tuple None
    特征:对象本身不能修改,一旦 “修改”,直接生成新对象,变量引用换新地址。
  5. 可变数据类型:列表 / 字典 / 集合 /bytearray字节数组
    可变对象:内存地址id固定,允许修改内部内容,引用不变
    原理:(列表)变量标签始终指向同一块列表内存,只是修改列表内部存储的元素引用
  6. 三种引用复制行为
    直接赋值:同引用(完全共享);只有一个内存对象,两个标签;任意修改可变对象,两边同步变化
    浅拷贝:外层新引用,内层共享引用;方式:list.copy() / lst[:] / list(lst) / copy.copy()
    a. 创建全新外层容器(外层 id 不同)
    b. 容器内部元素只复制引用地址,不新建对象
    c. 单层不可变元素看不出问题,嵌套可变列表会联动修改
    深拷贝:全部层级全新引用;方法:copy.deepcopy()
    递归创建每一层对象,所有层级内存地址都不同,完全隔离,互不影响
  7. is== 与引用的关系
    is:判断两个变量引用同一个对象(id 相等);
    ==:判断两个对象存储的值是否相等,不看引用;
    小整数缓存 -5~256:多个变量引用同一个数字对象,is为 True
  8. 函数传参:传递的是引用地址传递
    Python 参数传递统一为引用传递(传对象地址),不存在值传递
    传入不可变对象:函数内修改变量指向,外部不受影响
    传入可变对象:函数内修改内部数据,外部原对象同步变化
  9. 作用域与引用绑定
    a = 10
    def test():
        print(a)
        a = 20
    
    编译阶段扫描函数,发现a=20赋值,标记局部引用;运行时print(a)只会查找局部引用,局部还未绑定数据,报错;global a 强制声明:函数内 a 使用全局对象的引用
  10. 小结
    变量本质是对象的引用标签,赋值就是更换标签绑定的内存对象;
    不可变类型修改会生成新对象,引用地址改变;可变类型修改内部数据,引用地址不变;
    b=a 共享同一个引用;浅拷贝外层新引用、内层共享;深拷贝所有层级独立引用;
    is 判断是否同一引用,== 只判断值;
    函数传参传递对象引用,可变对象内部修改会影响外部;
    函数内出现赋值语句,变量标记为局部引用,优先查找局部空间。

迭代器与生成器

  1. 什么是可迭代对象Iterable
    能被 for 循环遍历、内部实现 __iter__() 方法的对象
    常见:列表、元组、字符串、字典、集合【不能直接用 next() 获取元素;可以重复循环,每次遍历从头开始】
  2. 什么是迭代器?
    迭代是Python访问集合中元素的一种方式,迭代器是一个可以记住遍历的位置的对象
    迭代器只能往前不会后退,如果迭代完了 继续迭代会报错;
    iter() 【创建迭代器】next()【迭代】
  3. 什么是迭代器Iterator
    两个条件:a. 实现 __iter__():返回自身;b. 实现 __next__():返回下一个元素,无元素时抛出 StopIteration
    获取迭代器:iter(可迭代对象);取值:next(迭代器)
  4. 把一个类作为一个迭代器使用需要在类中实现两个方法 __iter__()__next__()
    __iter__() 方法返回一个特殊的迭代器对象,这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成。
    __next__() 方法会返回下一个迭代器对象。
  5. 迭代器核心特性
    一次性消耗:元素取一个少一个,遍历完无法再次使用
    惰性取值,不会一次性把所有数据存入内存
    只能顺序向前,不能回退、不能索引取值
  6. 可迭代对象 vs 迭代器对比
    可迭代对象:iter、不可以next ()、可以重复遍历
    迭代器:iter、next、可以next ()、只能遍历一次
  7. 什么是生成器?
    在 Python 中,使用了 yield 的函数被称为生成器(generator)。
    生成器函数是一种特殊的函数,可以在迭代过程中逐步产生值,而不是一次性返回所有结果
    跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器
  8. 生成器 Generator(特殊迭代器)
    生成器本质是迭代器,自带 __iter____next__,无需手动实现
  9. 生成器创建方式
    a. 生成器函数(带 yield)-- 函数中不用 return,改用 yield 返回值
    b. 生成器表达式 (i for i in range(10))
  10. 生成器表达式()与列表推导式 []的区别
    列表一次性生成全部数据占用大量内存;生成器惰性生成(一次生成一个),省内存。
  11. yield
    yield 是一个关键字,用于定义生成器函数
    每次使用 yield 语句生产一个值后,函数都将暂停执行,等待被重新唤醒
    每次调用生成器的 next() 方法或使用 for 循环进行迭代时,函数会从上次暂停的地方继续执行,直到再次遇到 yield 语句
  12. yield的作用
    暂停函数执行,保存当前状态
    下次 next() 从暂停处继续运行
    逐个产出数据,不一次性加载全部内容
  13. yield与return
    yield 语句返回的是可迭代对象
    return 语句返回的为不可迭代对象
  14. yield 和 return 的区别
    return:直接终止函数,销毁局部变量,返回一次值
    yield:暂停函数,保留当前状态,下次 next 继续执行,可多次产出数据
  15. 迭代器与生成器核心共同点
    惰性计算,节省内存,适合超大序列、文件逐行读取
    一次性遍历,取完元素失效
    支持 fornext()
    底层都会抛出 StopIteration 结束循环
  16. 迭代器和生成器区别
    创建方式不同
    普通迭代器:手动实现类,重写 __iter____next__
    生成器:yield 函数 / () 推导式,自动生成迭代器
    代码复杂度
    迭代器:代码繁琐
    生成器:简洁,自动保存运行上下文
    状态保存
    普通迭代器需要自己定义变量记录下标;生成器由 yield 自动保存暂停位置
  17. for 循环遍历列表底层流程
    调用 iter(列表) 获取迭代器
    循环执行 next(迭代器)
    捕获 StopIteration 异常,结束循环
  18. 为什么迭代器只能遍历一次?
    每调用一次next(),内部指针向后移动一位,数据取出后不保存;指针走到末尾,再 next 直接报错,无法重置
  19. 生成器优点
    海量数据场景(百万行文件、超大数值序列),不用一次性加载全部数据到内存,内存占用极低
  20. 生成器能传参吗?send () 用法
    g.send(值) 可以向 yield 处传递数据
    def gen():
        res = yield 1	# 3. 只完成了右边 yield 1,左边赋值 res = 还没执行
    		       \# 5. 整个yield 1整体等价于 666,再执行res = 666 
        print(res) 	# 6. 最后打印666
    g = gen()	# 1. 调用生成器函数但不执行,暂停在函数开头 
    next(g)	# 2. 程序进入函数,运行到yield 1,产出1后暂停 
    g.send(666) # 4.唤醒函数,把 666 传入这个 yield 表达式(向内输入)```
    
  21. send(数据) 的作用:把传入的数据作为本次 yield 表达式的结果,赋值给左边变量,然后继续往下执行代码
  22. 生成器是迭代器,迭代器不一定是生成器
    生成器属于迭代器的子类;手动写的迭代器类不属于生成器
  23. 小结
    可迭代对象:能 for 循环,转迭代器才能 next
    迭代器:有__iter__、next,一次性遍历,惰性取值
    生成器:简化版迭代器,yield 函数 / 圆括号推导
    yield 暂停保存状态,return 直接结束函数
    超大数据优先用生成器,节约内存

类与对象

  1. 含义
    类(Class): 用来描述具有相同的属性和方法的对象的集合
    方法:类中定义的函数
    类变量:类变量在整个实例化的对象中是公用的
    数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据
    方法重写:从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写
    局部变量:定义在方法中的变量,只作用于当前实例的类
    实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。
    继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待
    实例化:创建一个类的实例,类的具体对象
    对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法
    关系:类是模板,对象是实例;一个类可以创建无数对象
  2. 类的定义
    类是一种自定义数据类型,用于创建对象
    类定义了对象的属性(数据成员)和方法(函数成员)
    通过class关键字定义类,类本身也是对象
  3. 对象的定义
    对象是类的实例,具有类定义的属性和方法
    通过调用类的构造函数来创建对象
    每个对象都有自己的状态,但共享相同的方法定义
    浅拷贝只会新建实例,内部引用共享;深拷贝完全独立
  4. self
    self是类方法的第一个参数,用于引用对象本身
    哪个对象调用方法,self 就代表哪个对象,用来区分不同实例的属性
  5. 属性(实例、类)
    属性是对象的特征或数据成员,用于存储对象的状态信息;可以通过点运算符访问或修改属性
    实例属性(绑定 self)-- 写在 __init__ / 实例方法里 self.xxx,每个对象独立一份,互不干扰
    类属性(写在类内部、方法外面)-- 属于类本身,所有对象共享同一份内存;对象读取不到实例属性时,会向上找类属性
    修改类属性:类名.属性 = 值
    对象.属性 = 值新建同名实例属性,不会改动类属性
  6. 方法
    方法是类中定义的函数成员,用于执行特定操作;通常与对象相关联,并可以访问对象的属性
    实例方法:第一个参数 self;只能由对象调用;可读写实例属性、访问类属性
    类方法 @classmethod:参数 cls,代表当前类;对象 / 类名都能调用;只能操作类属性,不能访问实例属性
    静态方法 @staticmethod:无默认参数 self/cls;和类、实例都无关,只是挂靠在类里的普通函数;不能访问实例、类属性
  7. 属性和方法统称为成员
    对象.属性 对象.方法
    类名.属性 类名.方法
  8. 对象.方法 -- 会默认传入一个实参,这个参数就是调用这个方法的对象
    类名.方法 -- 没有默认传入的实参,根据方法的形参传入实参
    无参方法只有类可以调用,对象调用无法传入对象参数
  9. 类方法
    类方法装饰器 -- @classmethod
    对象.方法,类名.方法 -- cls 都会自动接收当前类本身,不需要手动传
  10. 魔术方法
    __init__(self, ...):创建实例化对象时自动调用,初始化对象
    __add__(self, other) :对象进行+号运算时,自动调用
    __call__(self):对象被当作函数调用时,自动调用
    __getitem__(self, key):(取)对象索引它自己的下标取值时,会自动调用
    __setitem__(self, key, value):(存)对象索引它自己的下标并赋值时,会自动调用
    __del__(self):当对象被销毁时,自动调用
    __sub__(self, other):对象进行-号运算时,会自动调用
    __iter__(self):实现该方法的对象是可迭代对象,方法需要返回一个迭代器 -- 当使用 for 循环、iter()转换对象时,自动调用该方法
    __next__(self):仅迭代器拥有此方法,方法返回序列下一个元素,遍历完毕抛出StopIteration结束迭代 -- 每次执行next(迭代器)、for 循环获取下一个元素(取值)时自动调用
  11. 继承
    子类(派生类 DerivedClassName)会继承父类(基类 BaseClassName)的属性和方法
    语法: class 子类(父类):
    对象访问属性:对象==>所属类==>父类==>父类的父类==>......
  12. 多继承
    注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索,即方法在子类中未找到时,从左到右查找父类中是否包含方法;
    多继承的属性和方法的访问,按照继承顺序(继承链)依次访问(一条链找完了再找另一条)
  13. 多继承查找顺序 MRO
    使用 类名.__mro__ 查看查找顺序,遵循广度优先
  14. 重写
    父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法
    优先访问对象的属性 没有就访问类中的属性 再没有用就是父类中的属性
  15. super函数
    super 是一个全局函数,用于调用父类(超类)的一个方法
    调用时传入两个参数:参数1:一个类名 参数2:传入的类创建的一个对象
    super () 根据当前实例的 MRO 继承顺序,获取当前类之后的下一个类,调用该类的方法;需要 self 实例,不单是直接跳过当前类找父类。
  16. 类的私有属性和方法(封装)
    封装:把属性、方法装在类内部;通过访问控制隐藏内部细节,对外提供简单接口
    类内部的 __ 开头的自定义属性或者方法名,只能在类内部使用,不能在类外部访问使用
    可以先访问非私有方法,在非私有方法中去访问私有属性或方法
  17. self 实例方法,代表对象;cls 类方法,代表类
  18. 实例方法、类方法、静态方法使用场景
    操作实例属性用实例方法;统一操作类属性用类方法;和类无关工具函数用静态方法。
  19. __str____repr__ 区别?
    __str__ 面向用户友好输出,__repr__ 面向调试

装饰器

  1. 装饰器的本质?
    闭包和回调函数的语法糖
  2. 装饰器 @装饰函数 等价于:被装饰函数 = 装饰函数(被装饰函数)
  3. 带参的装饰器
    fn(2,3) # 参数是传给f的: fn(2,3)-->def f(2,3)-->cb(2**2,3**2)-->def fn(2,3)-->{4}*{9}={4*9}
    @tool@tool() 的区别: @tool ==》 @会自动调用tool; @tool() ==》 @会自动调用tool()
  4. 装饰器链
    执行顺序:从下往上(离函数近的先执行)
    执行顺序 ≠ 调用顺序
    装饰阶段(定义时):从下往上(@)
    调用阶段(执行时):从上往下
  5. 类装饰器(不带参)
    @Tool 这个语法糖会自动执行 fn=Tool(fn),而 Tool(fn) 就会创建实例对象
    fn = Tool(fn) -- 相当于创建对象,自动调用__init__方法,self=fn,n=fn
    装饰器过后fn就是对象了,所以fn()是对象被当作函数调用,因此会自动调用__call__方法
  6. 类装饰器(带参)
    Tool(10)创建 Tool 实例对象 obj,创建后自动调用__init__方法
    @objobj 是实例对象,obj() 调用 __call__ 方法,参数为原始函数 fn

包和模块

  1. 什么是模块?
    一个后缀为.py的python文件,里面可以存放变量、函数、类、执行代码。
    导入语法:import 模块名 / from 模块 import 内容
  2. 什么是包?
    存放多个模块的文件夹,文件夹里必须有 __init__.py 文件,才能被识别为 Python 包;
    包可以嵌套子包
  3. 模块和包的核心区别:
    模块:单个.py文件
    包:包含__init__.py的文件夹,由多个模块 / 子包组成
  4. __init__.py 三大核心作用
    标识文件夹为 Python 包,没有该文件无法 import 导入
    导入包时会自动执行这个文件内所有代码,做初始化配置
    通过 __all__ = ["模块1","模块2"] 控制 from 包 import * 能导入哪些模块
  5. 导入语法
    import 模块名 【as 别名】
    import 包名.模块名 【as 别名】
    from 模块名 import 标识符 【as 别名】
    from 包 import *
    from 包名 import 模块名 【as 别名】
    from 包名.模块名 import 标识符
  6. if __name__ == "__main__"
    文件直接运行__name__ = "__main__",if 内代码执行
    文件被其他文件 import 导入__name__ = 当前模块名,if 内代码不执行
    作用:存放测试代码,导入模块时不会自动执行测试逻辑
  7. 相对导入 . /..
    仅在包内部模块使用,不能在直接运行的主文件使用
    . 当前同级包目录;.. 上一级包目录
  8. 导入搜索路径 sys.path
    Python 导入模块时,按sys.path列表内路径依次查找
    可以手动追加路径:import sys; sys.path.append("自定义文件夹路径")
  9. 第三方包安装与管理
    安装:pip install 包名 [-i https://pypi.tuna.tsinghua.edu.cn/simple]
    导出依赖清单:pip freeze > requirements.txt
    批量安装依赖:pip install -r requirements.txt
posted @ 2026-07-14 18:37  桑年  阅读(2)  评论(0)    收藏  举报