python答辩复习
python基础知识
基础
- Python 依靠什么区分代码块?缩进规范是什么?缩进错误会怎样?
Python 依靠缩进区分代码块,不使用 {};规范推荐 4 个空格,也可用 1 个制表符;同一层级代码缩进量必须一致;缩进不一致会直接抛出缩进语法错误,程序无法运行。 - 基础类型(内置类型)
整数(int)、浮点数(float)、布尔值(bool)、字符串(str)、字节串(bytes)、空值(NoneType) - 引用类型(复合类型)
列表(list)、元组(tuple)、字典(dict)、集合(set)、枚举类型(Enum)、自定义类(class) - 变量基本类型
数字、字符串、列表、元组、集合、字典 - 变量保存的数据,有哪些类型的数据?
数字、布尔数据、字符串、None、列表、元组、字典、集合、函数、类、对象 - 变量的存值与取值
存值:a=10,变量不存在,在当前作用域创建,赋值初始化;变量存在则更新赋值
取值:取最近的一次
总结:变量存值,有就更新,没有就创建;变量取值,没有就报错,有就取出变量最近一次存的值 - 变量名、标识符
字母、数字、下划线,不能以数字开头
大小驼峰:agent_name、agentName、AgentName
不能使用Python的关键字作为标识符的名称
要区分大小写 - 变量的三个基本属性
id号:反映的是变量值的内存地址使用id()函数查看
类型:每一个变量都有自己的类型。
值:存储的数据。 - 变量的赋值与地址变化
a在创建时,被绑定到整数对象10(对于小整数,指向全局缓存池)。
创建b时,Python将b绑定到a所绑定的同一个对象上。
此时a和b是两个独立的变量标签,但它们指向同一块内存地址。 - 引用
变量名绑定到对象的地址,变量本身不存数据,只存对象地址。
赋值就是「新建引用」,不是复制对象 - 可变和不可变
不可变对象:int、float、str、tuple -- 对象创建后值不能修改,一旦修改,会创建新对象,旧引用不变。
可变对象:list、dict、set -- 对象本身能原地修改,所有指向它的引用全部同步变化 - 深浅拷贝(解决多引用共用对象问题)
当不想多个变量共用同一个可变对象时,使用拷贝生成新对象:
浅拷贝 :copy.copy ()/ 切片 [:] /list (),只拷贝第一层对象,内部嵌套元素依然共用引用
深拷贝 :copy.deepcopy (),递归拷贝所有层级,完全独立,没有共享引用 - 引用计数(垃圾回收底层原理)
每个对象自带一个引用计数器:记录当前有多少变量引用这个对象
计数 + 1 场景:对象赋值给变量a = [1,2]、作为参数传入函数func(a)、放入容器lst = [a]
计数 - 1 场景:变量重新赋值a = 100、变量删除del a、函数执行结束,局部变量销毁、容器被销毁
垃圾回收:当引用计数变为 0,Python 自动释放这块内存 - 函数传参:传递的是引用(值传递不存在)
Python 参数传递统一是引用传递(传对象地址)
传不可变对象:函数内修改只会新建对象,外部变量不变
传可变对象:函数内原地修改,外部同步变化 - del 关键字:删除引用,不是删除对象
del 变量名:只是切断变量和对象的绑定,对象引用计数 - 1;
只有计数为 0,对象才会被销毁。 - 注释
单行:#,快捷键Ctrl + /
多行:"""xxxx"""、'''xxx''' - 三单、三双引号能混用吗?
单双引号不能混合使用,否则语法报错。 - 关键字
Python解释器提前占用了的标识符,每一个关键字都有自己的特殊功能,比如常用的if、for、while、import、def等等。
可以通过调用Python的keyWord库来查看Python中的关键字都有哪些。 - 输出
基本输出、格式化输出(%)、formatl方法、f-string
formatl-- {:[填充][对齐][符号][宽度][,][.精度][类型]}
格式化 --m.n,m是用来控制输出数据的所占长度,n是用来控制输出数据的精度问题 - 可迭代对象
字符串、列表、元组、range、字节串、字节数组、集合、不可变集合、字典、文件/io对象、迭代器/生成器、自定义可迭代 - 不可迭代
整数int、浮点数float、布尔值bool、None都不能迭代,直接 for 循环会报错
基本类型
数字
-
数字的类型
整数、小数、复数、布尔
整数(int8 int16 int32 int64 uint8)
小数(float32 float64) -
进制
数字更长用的划分: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 -
二进制、八进制、十六进制数字开头标识是什么?对应转换函数?
二进制
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) -
源码、反码、补码
对于正数:
原码 = 反码 = 补码 = 二进制数
对于负数:
原码 = 二进制数
反码 = 原码符号位不变,其他位按位取反(0变1,1变0)
补码 = 反码 + 1 -
运算符分为哪几类
算数、位、比较、逻辑、赋值 -
运算符的优先级
运算符的优先级(从上向下排列,上面的优先级最高)
速记口诀:幂乘除加减,移位与异或,比较,非与或,赋值放最后圆括号():圆括号内的表达式拥有最高优先级
**:乘方运算
*、/、%、//:算术运算符,先乘除
+、-:算术运算符,后加减
<<、>>:位运算符的左移与右移
&:位运算符的按位与
^:位运算符的按位异或
|:位运算符的按位或
>、<、>=、<=、==、!=:比较运算符
not、and、or:逻辑运算符
=、+=等赋值运算符优先级最低
-
数学函数
引入模块: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) -
随机数
引入:import random
[0,1)范围内:random.random()
指定范围内:random.randrange (start, stop,step)
从序列的元素中随机挑选一个元素:random.choice(seq) -
三角函数
引入:import math
弧度转角度:math.degrees(x)
角度转弧度:math.radians(x)
字符串
- 字符串表达式
引号引起来的单引号、双引号、三引号(三个三引号或双引号) - 类型检测
字符串用type函数检测的结果为str - 转义字符
\r回车\n换行\t缩进\\表示
字符串前加r表示原始字符串:所见即所得,不转义 - 连接字符、输出字符
+、f-string、*、索引、切片、.format() - 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)
列表
- 切片
切片是浅拷贝操作,[含:不含:步长] - 修改、更新(添加)
list[2]=5;append() - 删除元素
del list[2] - 操作符/运算符--列表、元组
len()、+、*、in、for _ in [1,2,3] - API
len()、max()、min()、list() - 方法
append、count、extend、index、insert、pop、remove、reverse、sort、clear、copy - 引用数据的思想:
列表是一个引用数据:它会创建列表对象,占用内存空间
x = [10,20,30,40] -- 创建了一个列表对象,占用了一个内存空间
y = x -- 不会重新创建一个列表对象,也就是说不会新开辟内存空间
y[1] = 666
print(x) -- [10,666,30,40]
元组
- 元组不可变(不可修改),可以有不同类型的数据,但如果嵌套可变数据,该可变数据可以修改
- 解构赋值:
当等号左侧只有一个变量,右侧多个数据用逗号分隔(无外层容器) 时,Python 会自动将右侧整体封装为元组再赋值
按照索引顺序,依次赋值给等号左边的变量(一次多个变量的语法) - 元组中只包含一个元素时,需要在元素后面添加逗号 ,否则括号会被当作运算符使用
- 对元组进行连接组合:
+ - 元组元素不可单个删除,但可以用
del删除整个元组 - API:
len()、max()、min()、tuple()
字典
- 键必须是唯一的,但值则不必;值可以取任何数据类型,但键必须是不可变的,如字符串,数字
- 访问
dic[key]--没有会报错
dict.get(key, default=None)--返回值,没有返回默认值
dict.items()--以列表返回一个视图对象 -- dict_items([('Name', 'hqyj'), ('Age', 8), ('Class', 'First')])
dict.keys()--返回一个视图对象
dict.values()--返回一个视图对象 - 修改
mydic = {'Name': 'hqyj', 'Age': 7, 'Class': 'First'} mydic['Age'] = 8 # 更新 mydic['School'] = "华清" #添加信息``` - 删除
del mydic['Name'] # 删除键 'Name' mydic.clear() # 清空字典 del mydic # 删除字典``` - 特性
不允许同一个键出现两次。创建时如果同一个键被赋值两次,后一个值会被记住
键必须不可变,所以可以用数字,字符串或元组充当,而用列表就不行 - API
len()、srt()、type() - 方法
clear、copy、get、key in dict、setdefault、update、pop、popitem()
返回视图:items、key、values
集合
- 无序的不重复元素序列,可以进行交集&、并集|、差集-等常见的集合操作
- 使用大括号 { } 创建集合,元素之间用逗号 , 分隔, 或者也可以使用 set() 函数创建集合
- 创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典
- 添加
s.add(x):添加元素到集合
s.update(x):添加元素到集合,且参数可以是列表,元组,字典等,x 可以有多个,用逗号分开 - 移除
s.remove(x):将元素 x 从集合 s 中移除,如果元素不存在,则会发生错误。
s.discard(x):将元素 x 从集合 s 中移除,如果元素不存在,不会发生错误。
s.pop():对集合进行无序的排列,然后将这个无序排列集合的左面第一个元素进行删除。 - 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()
条件、循环
- range
生成一个整数序列,序列中的每个元素按照指定的步长递增
并不会真正创建一个列表,而是返回一个可迭代的对象——range对象 - for
迭代遍历可迭代对象(如列表、字符串、字典等) - while
条件为真时重复执行代码块 - 循环控制
break:用于跳出当前循环;continue:用于跳过当前迭代,继续下一次迭代。 - pass
占位符
python高级技巧
推导式
-
enumerate():全局函数,获取序列的索引和元素 -
if在for后面:作为过滤条件,满足则保留元素,不满足则丢弃(不需要else) -
if在for前面(即冒号后面的值表达式):作为三元条件表达式,必须带else,含义是:-
条件满足 → 返回
if前面的值 -
条件不满足 → 返回
else后面的值
-
列表推导式
- 语法(基本格式)
[表达式 for 变量 in 序列]
[表达式 for 变量 in 序列 if 条件]
[表达式 for 变量1 in 容器1 for 变量2 in 容器2(可以是变量1)]
字典推导式
- 基本格式
{ key_expr: value_expr for value in collection }
{ key_expr: value_expr for value in collection if condition }
集合推导式
- 基本格式
{ expression for item in Sequence }
{ expression for item in Sequence if conditional }
元组推导式
- 基本格式
(expression for item in Sequence )
(expression for item in Sequence if conditional )
生成器表达式
- 语法
(表达式 for 变量 in 序列 if 条件)
使用圆括号,返回生成器对象,节省内存 - 使用next()获取值
- 按需生成,不占用大量内存
函数
定义、参数
- 调用函数代码运行后,才会把函数中的代码运行一遍,而且相互独立
函数调用一次,就会重新运行一次;函数不调用,函数中的代码就不会执行 - 文档字符串:三引号(
"""/''')写在函数、类、文件最开头的注释文本,属于字符串对象,专门用来描述功能、参数、返回值,区别于普通单行注释#。 - return [表达式] 结束函数,选择性地返回一个值给调用方,不带表达式的 return 相当于返回 None
函数return多个值时,用逗号分隔,Python 自动打包成元组返回 - 参数类型
必需参数、默认参数(形参)、可变参数、关键字参数(实参) - 参数位置
必须按先后顺序:位置参数、关键字参数、*修饰符参数(剩余位置参数--元组)、**修饰符参数(剩余关键字参数--字典)
*占位的参数(后面:关键字参数)、/占位的参数(前面:位置参数)
默认值参数:必须放在没有默认值参数的后面 - 形参和实参
函数调用时形参变量不能多次赋值,但是执行时可以
函数调用时,形参变量必须有值(1.传入 2.默认值)
传入的数据不允许超过形参变量的数量
调用函数传入的数据叫实际传入的参数,称之为实参 - 可变数据类型:列表、字典、集合、函数、类、实例对象、
bytearray字节数组;
其余基础类型(数字、布尔、复数、字符串、元组、None、bytes字节串)均为不可变类型。 - 不可变类型(值传递): 如整数、字符串、元组。
可变类型(引用传递): 如 列表,字典。
python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。 yeild关键字
函数内部yeild关键字 会让函数产生生成器对象数据- 匿名函数 -
lamda函数
函数定义时没有名字时使用
语法:lambda arguments: expression
冒号前面是形参的变量名,冒号后面是函数内部要执行的代码,代码结果为函数返回值
作用域
- 函数的作用域
一个变量和一个函数在哪些地方可以被访问使用,那些地方就是他们起作用的代码区域,也叫作用域 - 函数内部写代码可以使用函数内部的变量和函数,也可以使用函数外部的变量和函数
函数外部写代码可以使用函数外部的变量和函数,不能使用函数内部的变量和函数 - 作用域最难的一句总结:
函数在A作用域定义 在B作用域中调用 运行代码是在它定义的地方(A作用域) - 局部变量和全局变量
如果在函数内部,操作变量给它存值,希望操作的变量时外部的变量,只能使用两个关键字global和nonlocal
global:在函数内部提前声明,该变量无论取值还是存值,都是全局变量
nonlocal:在嵌套函数内部提前声明,该变量不是当前作用域的变量,无论取值还是存值,都只操作上层变量,上层没有就操作上层的上层,直到全局都没有就报错(不会操作全局变量) - LEGB 查询顺序是什么?举例子说明
查找变量顺序:局部 L → 外层嵌套 E → 全局 G → 内置 B。
先从当前函数内部找,找不到一层层向外,最后找系统内置名称,全部找不到报错。 - 函数调用结束后,局部变量还存在吗?
普通函数执行完毕,局部作用域销毁,局部变量回收,无法外部访问;只有闭包会保留外层函数变量环境。 - 什么是闭包?闭包和作用域的关系?
闭包:嵌套内部函数,引用了外层函数的局部变量,外层函数执行结束后,外层变量不会被销毁。
原理:内部函数保存了外层作用域环境,延长局部变量生命周期。 - 函数内只要出现
变量=值赋值,无论在什么位置,该变量在定义函数的时候就会直接被判定为局部变量
闭包、自调用、重复调用
- 什么是闭包?满足 3 个条件就是闭包
存在嵌套函数(内层函数、外层函数)
内层函数引用外层函数的局部变量(非全局变量)
外层函数返回内层函数对象 - 普通函数执行完,局部变量直接销毁;
闭包会保存外层函数作用域、变量引用,外层函数执行结束,变量不会回收,内层函数持续使用。 - nonlocal 和闭包
内层想要修改外层变量,必须加nonlocal,否则判定为局部变量报错 - 闭包优点
封装私有数据,外部无法直接修改外层变量
延长变量生命周期,不用全局变量 - 闭包缺点
变量长期占用内存,不手动释放会造成内存浪费
结构复杂,可读性下降 - 闭包是嵌套内层函数引用外层局部变量,外层返回内层函数;可保存外层作用域数据,修改外层变量需要 nonlocal 关键字
- 什么是回调函数?
把函数 A 当作参数传递给另一个函数 B,在 B 内部自动调用 A,A 就是回调函数 - 回调函数常用场景
sorted的 key 参数(lambda 回调)
定时器、异步任务、GUI 按钮点击事件
数据处理、接口请求成功 / 失败回调 - 匿名函数 lambda 常用作简易回调
简短逻辑不需要单独定义函数,直接传 lambda - 区分:回调 vs 普通函数调用
普通调用:代码主动写func()
回调:函数由其他函数内部自动触发执行 - 普通函数重复调用:每次全新局部作用域
每次调用函数都会开辟独立局部空间,上次调用的局部变量全部销毁,互不干扰。 - 闭包重复调用:会保留状态(记忆上次数据)
多次调用同一个闭包实例,变量持续累加;如果重新创建新闭包,会重置数据 - 递归调用(特殊重复调用)
函数自己调用自己,必须设置终止条件,否则无限递归报错
缺点:递归深度有限,大量重复调用容易栈溢出 - 重复调用带来的性能问题
普通函数:每次执行都要重新创建局部变量、重复计算,效率低
解决方案:缓存(装饰器 lru_cache),相同参数重复调用直接读取缓存结果,不用重复计算 - 全局变量实现调用计数(不推荐,对比闭包)
缺点:全局变量污染,多函数共用容易冲突,优先使用闭包
引用
- 核心概念:变量是引用标签,数据在内存
- 核心名词
数据(对象):内存中真实存在的值,有独立 id(内存地址),分可变 / 不可变。
数字、字符串、列表、字典都叫对象。
变量(引用标签):变量不是盒子,只是贴在对象上的标签 / 引用;
a = 10:在内存创建整数对象10,把标签a贴到这个对象上 - 赋值本质:修改引用绑定
- 基础数据类型:不可变对象的引用规则
不可变类型:int float bool str tuple None
特征:对象本身不能修改,一旦 “修改”,直接生成新对象,变量引用换新地址。 - 可变数据类型:列表 / 字典 / 集合 /
bytearray字节数组
可变对象:内存地址id固定,允许修改内部内容,引用不变
原理:(列表)变量标签始终指向同一块列表内存,只是修改列表内部存储的元素引用 - 三种引用复制行为
直接赋值:同引用(完全共享);只有一个内存对象,两个标签;任意修改可变对象,两边同步变化
浅拷贝:外层新引用,内层共享引用;方式:list.copy()/lst[:]/list(lst)/copy.copy()
a. 创建全新外层容器(外层 id 不同)
b. 容器内部元素只复制引用地址,不新建对象
c. 单层不可变元素看不出问题,嵌套可变列表会联动修改
深拷贝:全部层级全新引用;方法:copy.deepcopy()
递归创建每一层对象,所有层级内存地址都不同,完全隔离,互不影响 is和==与引用的关系
is:判断两个变量引用同一个对象(id 相等);
==:判断两个对象存储的值是否相等,不看引用;
小整数缓存-5~256:多个变量引用同一个数字对象,is为 True- 函数传参:传递的是引用(地址传递)
Python 参数传递统一为引用传递(传对象地址),不存在值传递
传入不可变对象:函数内修改变量指向,外部不受影响
传入可变对象:函数内修改内部数据,外部原对象同步变化 - 作用域与引用绑定
编译阶段扫描函数,发现a = 10 def test(): print(a) a = 20a=20赋值,标记局部引用;运行时print(a)只会查找局部引用,局部还未绑定数据,报错;global a强制声明:函数内 a 使用全局对象的引用 - 小结
变量本质是对象的引用标签,赋值就是更换标签绑定的内存对象;
不可变类型修改会生成新对象,引用地址改变;可变类型修改内部数据,引用地址不变;
b=a共享同一个引用;浅拷贝外层新引用、内层共享;深拷贝所有层级独立引用;
is判断是否同一引用,==只判断值;
函数传参传递对象引用,可变对象内部修改会影响外部;
函数内出现赋值语句,变量标记为局部引用,优先查找局部空间。
迭代器与生成器
- 什么是可迭代对象
Iterable?
能被for循环遍历、内部实现__iter__()方法的对象
常见:列表、元组、字符串、字典、集合【不能直接用next()获取元素;可以重复循环,每次遍历从头开始】 - 什么是迭代器?
迭代是Python访问集合中元素的一种方式,迭代器是一个可以记住遍历的位置的对象
迭代器只能往前不会后退,如果迭代完了 继续迭代会报错;
iter()【创建迭代器】和next()【迭代】 - 什么是迭代器
Iterator?
两个条件:a. 实现__iter__():返回自身;b. 实现__next__():返回下一个元素,无元素时抛出StopIteration
获取迭代器:iter(可迭代对象);取值:next(迭代器) - 把一个类作为一个迭代器使用需要在类中实现两个方法
__iter__()与__next__()。
__iter__()方法返回一个特殊的迭代器对象,这个迭代器对象实现了__next__()方法并通过StopIteration异常标识迭代的完成。
__next__()方法会返回下一个迭代器对象。 - 迭代器核心特性
一次性消耗:元素取一个少一个,遍历完无法再次使用
惰性取值,不会一次性把所有数据存入内存
只能顺序向前,不能回退、不能索引取值 - 可迭代对象 vs 迭代器对比
可迭代对象:iter、不可以next ()、可以重复遍历
迭代器:iter、next、可以next ()、只能遍历一次 - 什么是生成器?
在 Python 中,使用了yield的函数被称为生成器(generator)。
生成器函数是一种特殊的函数,可以在迭代过程中逐步产生值,而不是一次性返回所有结果
跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器 - 生成器
Generator(特殊迭代器)
生成器本质是迭代器,自带__iter__和__next__,无需手动实现 - 生成器创建方式
a. 生成器函数(带 yield)-- 函数中不用return,改用yield返回值
b. 生成器表达式(i for i in range(10)) - 生成器表达式
()与列表推导式[]的区别
列表一次性生成全部数据占用大量内存;生成器惰性生成(一次生成一个),省内存。 - yield
yield是一个关键字,用于定义生成器函数
每次使用yield语句生产一个值后,函数都将暂停执行,等待被重新唤醒
每次调用生成器的next()方法或使用for 循环进行迭代时,函数会从上次暂停的地方继续执行,直到再次遇到 yield 语句 - yield的作用
暂停函数执行,保存当前状态
下次next()从暂停处继续运行
逐个产出数据,不一次性加载全部内容 - yield与return
yield 语句返回的是可迭代对象
return 语句返回的为不可迭代对象 - yield 和 return 的区别
return:直接终止函数,销毁局部变量,返回一次值
yield:暂停函数,保留当前状态,下次 next 继续执行,可多次产出数据 - 迭代器与生成器核心共同点
惰性计算,节省内存,适合超大序列、文件逐行读取
一次性遍历,取完元素失效
支持for、next()
底层都会抛出StopIteration结束循环 - 迭代器和生成器区别
创建方式不同:
普通迭代器:手动实现类,重写__iter__、__next__
生成器:yield 函数 / () 推导式,自动生成迭代器
代码复杂度:
迭代器:代码繁琐
生成器:简洁,自动保存运行上下文
状态保存:
普通迭代器需要自己定义变量记录下标;生成器由 yield 自动保存暂停位置 - for 循环遍历列表底层流程
调用iter(列表)获取迭代器
循环执行next(迭代器)
捕获StopIteration异常,结束循环 - 为什么迭代器只能遍历一次?
每调用一次next(),内部指针向后移动一位,数据取出后不保存;指针走到末尾,再 next 直接报错,无法重置 - 生成器优点
海量数据场景(百万行文件、超大数值序列),不用一次性加载全部数据到内存,内存占用极低 - 生成器能传参吗?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 表达式(向内输入)``` send(数据)的作用:把传入的数据作为本次 yield 表达式的结果,赋值给左边变量,然后继续往下执行代码- 生成器是迭代器,迭代器不一定是生成器
生成器属于迭代器的子类;手动写的迭代器类不属于生成器 - 小结
可迭代对象:能 for 循环,转迭代器才能 next
迭代器:有__iter__、next,一次性遍历,惰性取值
生成器:简化版迭代器,yield 函数 / 圆括号推导
yield 暂停保存状态,return 直接结束函数
超大数据优先用生成器,节约内存
类与对象
- 含义
类(Class): 用来描述具有相同的属性和方法的对象的集合
方法:类中定义的函数
类变量:类变量在整个实例化的对象中是公用的
数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据
方法重写:从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写
局部变量:定义在方法中的变量,只作用于当前实例的类
实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。
继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待
实例化:创建一个类的实例,类的具体对象
对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法
关系:类是模板,对象是实例;一个类可以创建无数对象 - 类的定义
类是一种自定义数据类型,用于创建对象
类定义了对象的属性(数据成员)和方法(函数成员)
通过class关键字定义类,类本身也是对象 - 对象的定义
对象是类的实例,具有类定义的属性和方法
通过调用类的构造函数来创建对象
每个对象都有自己的状态,但共享相同的方法定义
浅拷贝只会新建实例,内部引用共享;深拷贝完全独立 - self
self是类方法的第一个参数,用于引用对象本身
哪个对象调用方法,self就代表哪个对象,用来区分不同实例的属性 - 属性(实例、类)
属性是对象的特征或数据成员,用于存储对象的状态信息;可以通过点运算符访问或修改属性
实例属性(绑定 self)-- 写在__init__/ 实例方法里self.xxx,每个对象独立一份,互不干扰
类属性(写在类内部、方法外面)-- 属于类本身,所有对象共享同一份内存;对象读取不到实例属性时,会向上找类属性
修改类属性:类名.属性 = 值
用对象.属性 = 值会新建同名实例属性,不会改动类属性 - 方法
方法是类中定义的函数成员,用于执行特定操作;通常与对象相关联,并可以访问对象的属性
实例方法:第一个参数self;只能由对象调用;可读写实例属性、访问类属性
类方法@classmethod:参数cls,代表当前类;对象 / 类名都能调用;只能操作类属性,不能访问实例属性
静态方法@staticmethod:无默认参数self/cls;和类、实例都无关,只是挂靠在类里的普通函数;不能访问实例、类属性 - 属性和方法统称为成员
对象.属性 对象.方法
类名.属性 类名.方法 - 对象.方法 -- 会默认传入一个实参,这个参数就是调用这个方法的对象
类名.方法 -- 没有默认传入的实参,根据方法的形参传入实参
无参方法只有类可以调用,对象调用无法传入对象参数 - 类方法
类方法装饰器 --@classmethod
对象.方法,类名.方法 --cls都会自动接收当前类本身,不需要手动传 - 魔术方法
__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 循环获取下一个元素(取值)时自动调用 - 继承
子类(派生类DerivedClassName)会继承父类(基类BaseClassName)的属性和方法
语法:class 子类(父类):
对象访问属性:对象==>所属类==>父类==>父类的父类==>...... - 多继承
注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索,即方法在子类中未找到时,从左到右查找父类中是否包含方法;
多继承的属性和方法的访问,按照继承顺序(继承链)依次访问(一条链找完了再找另一条) - 多继承查找顺序 MRO
使用类名.__mro__查看查找顺序,遵循广度优先 - 重写
父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法
优先访问对象的属性 没有就访问类中的属性 再没有用就是父类中的属性 - super函数
super 是一个全局函数,用于调用父类(超类)的一个方法
调用时传入两个参数:参数1:一个类名 参数2:传入的类创建的一个对象
super () 根据当前实例的 MRO 继承顺序,获取当前类之后的下一个类,调用该类的方法;需要 self 实例,不单是直接跳过当前类找父类。 - 类的私有属性和方法(封装)
封装:把属性、方法装在类内部;通过访问控制隐藏内部细节,对外提供简单接口
类内部的__开头的自定义属性或者方法名,只能在类内部使用,不能在类外部访问使用
可以先访问非私有方法,在非私有方法中去访问私有属性或方法 self实例方法,代表对象;cls类方法,代表类- 实例方法、类方法、静态方法使用场景
操作实例属性用实例方法;统一操作类属性用类方法;和类无关工具函数用静态方法。 __str__和__repr__区别?
__str__面向用户友好输出,__repr__面向调试
装饰器
- 装饰器的本质?
闭包和回调函数的语法糖 - 装饰器
@装饰函数等价于:被装饰函数 = 装饰函数(被装饰函数) - 带参的装饰器
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() - 装饰器链
执行顺序:从下往上(离函数近的先执行)
执行顺序 ≠ 调用顺序
装饰阶段(定义时):从下往上(@)
调用阶段(执行时):从上往下 - 类装饰器(不带参)
@Tool 这个语法糖会自动执行fn=Tool(fn),而Tool(fn)就会创建实例对象
fn = Tool(fn)-- 相当于创建对象,自动调用__init__方法,self=fn,n=fn
装饰器过后fn就是对象了,所以fn()是对象被当作函数调用,因此会自动调用__call__方法 - 类装饰器(带参)
先Tool(10)创建Tool实例对象obj,创建后自动调用__init__方法
再@obj,obj是实例对象,obj()调用__call__方法,参数为原始函数fn
包和模块
- 什么是模块?
一个后缀为.py的python文件,里面可以存放变量、函数、类、执行代码。
导入语法:import 模块名/from 模块 import 内容 - 什么是包?
存放多个模块的文件夹,文件夹里必须有__init__.py文件,才能被识别为 Python 包;
包可以嵌套子包 - 模块和包的核心区别:
模块:单个.py文件
包:包含__init__.py的文件夹,由多个模块 / 子包组成 __init__.py三大核心作用
标识文件夹为 Python 包,没有该文件无法 import 导入
导入包时会自动执行这个文件内所有代码,做初始化配置
通过__all__ = ["模块1","模块2"]控制from 包 import *能导入哪些模块- 导入语法
import 模块名 【as 别名】
import 包名.模块名 【as 别名】
from 模块名 import 标识符 【as 别名】
from 包 import *
from 包名 import 模块名 【as 别名】
from 包名.模块名 import 标识符 if __name__ == "__main__"
文件直接运行:__name__ = "__main__",if 内代码执行
文件被其他文件 import 导入:__name__ = 当前模块名,if 内代码不执行
作用:存放测试代码,导入模块时不会自动执行测试逻辑- 相对导入 . /..
仅在包内部模块使用,不能在直接运行的主文件使用
.当前同级包目录;..上一级包目录 - 导入搜索路径
sys.path
Python 导入模块时,按sys.path列表内路径依次查找
可以手动追加路径:import sys; sys.path.append("自定义文件夹路径") - 第三方包安装与管理
安装:pip install 包名 [-i https://pypi.tuna.tsinghua.edu.cn/simple]
导出依赖清单:pip freeze > requirements.txt
批量安装依赖:pip install -r requirements.txt
本文来自博客园,作者:桑年,转载请注明原文链接:https://www.cnblogs.com/clover-1105/p/21466182

浙公网安备 33010602011771号