格式:
if 条件: true环境
规则:
条件为真, 则执行true环境
条件为假, 则跳过true环境
分析:
条件就是一个表达式, 例如: 比较, 赋值, 逻辑 …
最终条件只有两个结果: true 和 false
if 条件:
true环境 (代码块)
代码块: 一行或者多行代码, 但不能不写
if 条件:
true环境
else:
false环境
规则:
条件为真, 则执行true环境
条件为假, 则执行false环境
if 条件:
true环境 (代码块)
elif 条件2:
true2环境 (代码块)
elif 条件3:
true3环境 (代码块)
…
多个条件满足一个即可进入代码块
例如: 男生挑女朋友!!
长得好看吗
身材好吗
温柔乖巧吗
姿势多吗
if 条件:
true环境 (代码块)
elif 条件2:
true2环境 (代码块)
elif 条件3:
true3环境 (代码块)
…
多个条件满足一个即可进入代码块
例如: 男生挑女朋友!!
长得好看吗
身材好吗
温柔巧吗
姿势多吗
循环:
作用: 将某一部分的代码功能, 重复的执行, 直到不满足某些条件时, 终止循环
好处: 偷懒, 减少代码量
while 1.条件:
2.true环境 (代码块)
条件成立, 则进入true环境
条件不成立, 则结束循环, 准备执行while外面的代码
while 条件: true环境 仅适合简单功能
一条命令独占一行, 一般不允许同在一行
若强制同在一行, 每条命令之间用 分号 隔开
死循环, 无限循环: 条件永远成立 例如True, 1 …
在未来实时请求时, 非常有用
例如: 游戏人物对话, 按回车才能进行下一步
例如: 循环次数不确定时, 当满足某些指定条件时, 在循环中通过一些特殊手段来终止循环
while ①条件:
②true环境 (代码块)
else:
③false环境 (代码块)
执行顺序:成立: 则执行 ②
条件① 不成立: 则执行 ③
for 变量 in 容器:
代码块
容器: list, tuple, set, dict
这里也可以填 string
变量 会一次获取容器中一个值
for 变量 in 容器:
代码块
else:
进阶体
这里的else是值: 当循环完了就立马进入else
for 变量 in 数字区间:
代码块
数字区间:
range(start, stop, step)
参数:
start: 从start开始, 默认从0开始
stop: 到stop结束, 不包括stop
step: 步长, 默认为1
将代码组织在一起, 从而实现一个完整的功能
功能相似, 位置相同, 用循环
功能相似, 位置不同, 用函数
可重复利用, 降低冗余率
提高开发效率
便于代码维护
内置函数: 内建函数, 系统函数, 编程语言自带的, 可以直接使用
自定义函数: 根据实际需求而创造的函数
格式:
def 函数名( 参数1, 参数2, … ):
函数体,代码块
注意:
函数体一定要缩进
组成:
关键字: def 函数名 参数 函数体 返回值
不调用不执行
函数可以互相调用, 却互不影响
调用函数的位置 必须在 定义函数位置的后面 (有顺序要求)
执行原理:
先调用函数
再执行函数体,代码块
当代码块全部执行完毕后, 回到调用函数的地方
函数名()
由数字, 字母和下划线组成,不能以数字开头,严格区分大小写,命名形式
参考: PEP
注意点:
1.函数重名
2.调用函数, 会调用前面最近的一个指定函数
3.函数可以覆盖, 后面的覆盖前面的
4.尽量别重名
4.2 函数名意义
为了后期的维护, 提高代码的可读性, 函数名最好通俗易懂
看到名字就大致知道什么功能
惯性:
函数名习惯以 动词+名词 形式出现
1.关键字: return:函数中的值 返回到调用函数的地方
2.作用:提前结束函数, 并返回, return 后面的代码将不再执行
1.return 可以返回任意类型
2.多返回值
return 值1, 值2, …)
return [值1, 值2, …]
return {值1, 值2, …}
需要一次性返回多个值:
1) 将多个值 以逗号隔开
2) 将值 包装到list, tuple, set 中
3.如果函数 没有return, 默认返回None
1.定义
参数: 能用将函数功能进行微弱的变化, 从而达到通用的效果
形参: 在定义函数时给的参数 (parameter)
实参: 在调用函数时给的参数 (argument)
2.参数传递
1.值 和 传址
传值: 仅仅是将值 传递过去
传址: 不仅将值 传递过去, 而且将内存地址传递过去
2.区分:
传值: 不可变数据类型 (Number, string, tuple, set)
传址: 可变数据类型 (list, dict)
3.参数类型
1.必须参数
实参个数 = 形参个数 (参数个数必须一致)
先到先得
2.关键字参数
实参指定 参数名来传入
好处: 不用按照顺序来传入
3.默认参数
即便实参没有传值, 形参可以采用默认值
4.不定长参数
在形参前面加 * , 以元组形式接收没人要的实参
在形参前面加 **, 以字典形式接收没人要的关键字实参
单独出现 * , 在*后面的参数必须以关键字实参进行传入
且关键字 必须与 形参名 一致
没有名字的函数
场景: 功能太简单, 又不想写def, 不用取函数名
lambda 形参 : 返回值
冒号左边: 想要传递的参数
冒号右边: 需要return的结果
注意: lambda是一个表达式, 并非语句, 用在def不能用的地方
小结:
lambda 用于简单功能
def 用于复杂功能
在函数外部定义的变量
在函数内部定义的变量
查询规则:
L -> E -> G -> B
仅仅是访问, 不代表修改或删除
x = int(10.5) # 内置作用域 B
a = 0 # 全局作用域 G
def outer():
b = 1 # 闭包函数外的函数内 E
print('b的变量: %d ' % b)
def inner():
c = b # 局部作用域 L
c = a
print('c的变量: %d' % c) # L 区间能找到E区间的变量
# L 区间能找到G区间的变量
inner()
# print('c的变量: %d' % c) # E 区间找不到L区间的变量
outer()
print('a的变量: %d' % a)
# print('b的变量: %d' % b) # G 区间不能找到 E区间的变量
在作用域E中, 不能直接改变全局变量, 通过global声明一下, 就可以改变全局变量
注意点:
global a 之后, 全局a 和 global a 公用一个内存
而在E 区间中, 单独写 a = 15, 仅仅是给E区间中声明一个新的变量a, 该变量a 与 全局a 内存不一样
如果仅仅是访问全局a , 不需要global声明
L 区间可以访问E区间的变量, 不能直接改变E区间的变量, 通过 nonlocal来声明一下就可以改变E区间的变量
小结:
需要改变作用G 中的变量, 则通过global
需要改变作用E 中的变量, 则通过nonlocal
代码案例:
a = 10 # G 区间
def outer():
b = 5 # E 区间
global a
a += b
print(a)
outer()
print(a)
a = 10
def outer():
b = 55 # E区间
def inner():
nonlocal b
b += 5 # L区间
print(b)
inner()
outer()
函数A 里面定义了一个新的函数B
函数B 使用函数A的变量
只要满足以上两个条件, 函数B就是一个闭包函数
例如:
def A():
a = 10
def B():
print(a) # 使用函数A的变量, 那么此时函数B, 就成为了 闭包函数
# 通俗说法: 函数A 常被称之为: 外部函数
# 函数B 常被称之为: 内部函数
直接调用
def A():
a = 10
def B():
b = 20
b += a
print(b)
B() # 直接调用
A()
def A():
a = 10
def B():
b = 20
b += a
print(b)
return B # 返回的是 函数B
result = A() # result = 函数B
result()
result()
分析:
当执行完53行, 到54行时, A() 已经执行完毕了.
由于返回的是函数, 导致了函数B内的变量, 依旧占用内存
默认情况下, 一个函数结束时, 函数内的变量应该是 全部释放(删除)
优点: 数据的持久化
缺点: 因为持久化, 没哟及时释放内存, 所以一直占用内存, 浪费了性能
闭包函数不能直接修改外部函数的变量
int()
float()
bool()
complex()
str()
list()
tuple()
set()
dict()
id() 获取变量的内存地址
type() 获取变量的数据类型
print() 输出变量
locals() 获取当前作用域中的所有变量
abs()
sum()
max()
min()
pow()
round()
range()
hex() 十六进制
oct() 八进制
bin() 二进制
chr() ascii => 字符
ord() 字符 => ascii
repr() 原始字符串
eval() 解析字符串 (能够将字符串 当成公式执行. 例如含有变量, 那么就会解析变量)
方法就是函数
对象: 一切皆对象
字符串方法
对象.方法名()
方法就是函数
对象: 一切皆对象
.upper() 全部转为大写
.lower() 全部转为小写
.capitalize() 首字母大写
.title() 每个单词的首字母大写
.isalnum() 只能有数字, 字母 , 中文
.isalpha() 只能有字母, 中文
.isdigit() 只能有数字
.isupper() 检测是否为大写
.islower() 检测是否为小写
a = '{},{},{}高高兴兴牵着手, 一起冲向女厕所'
print(a)
print(a.format('熊大', '熊二', '光头强') )
a = '{0},{1},{2}高高兴兴牵着手, 一起冲向女厕所'
a = '{2},{1},{0}高高兴兴牵着手, 一起冲向女厕所'
a = '{1},{2},{0}高高兴兴牵着手, 一起冲向女厕所'
print(a.format('熊大', '熊二', '光头强') )
a = '{name}头顶{2}, 身披{pro1},'锅盖', pro2='麻袋', pro3='白菜'))
print(a.format(pro1='锅盖', pro2='麻袋', pro3='白菜', name='狗蛋'))
a = '{0}头顶{1}, 身披{pro2}, 脚踩{pro3}, 吾称屌丝二代'
print( a.format('二狗', '锅盖', pro2='麻袋', pro3='白菜' ) )
# print( a.format( pro2='麻袋', pro3='白菜', '二狗', '锅盖') )
print( a.format('二狗', '锅盖', pro3='白菜', pro2='麻袋' ) )
{a:bcd}
a: 索引/关键字
b: 填充符号 默认 空字符串
c: 对齐符号 左< 右> 居中^
d: 总长度
如果a 比 d 还长, 那么bc就看不出来, 以实际a 的长度为准
如果a 比 d 还小, 那么不够的长度用b来填
b: 二进制
o: 八进制
d: 十进制
x: 十六进制
格式: {:b}
格式: {?}
格式: {:d}
格式: {:x}
格式: {:.num} 整数+小数 一共num位
格式: {:.numf} 小数 一共num位
注意点:
冒号 后面有一个 小数点
a = '马云身价${:,}'
print(a.format(10000000000000))
由一堆数据组成的有序序列
变量名 = [值1, 值2, 值3, … ]
值: 可以为任意类型
1.通过 索引 来访问列表
格式:
变量名[索引]
2.通过索引来修改
a[2] = '生煎包' # 索引存在时, 才能修改
# a[99] = '奶黄包' # 索引不存在时, 则报错
print(a)
3.通过索引来删除
del a[2] # 删除索引为2 的值
print(a)
print(a[2]) # 前面的索引2 被删除的同时, 后面的索引依次向前进一
# del a[99] # 删除不存在的索引时, 则报错
4.插入列表
插入已有的索引
变量名.insert(索引, 值)
插入不存在的索引,会当做已有最大索引+1处理
插入最大的索引或在最后面加一个索引
变量名.append(值)
小结:
如果知道索引, 用insert
如果只是想追加一个索引, 用append
# 4.1 列表合并 +
a = ['刘德华', '张学友']
b = ['郭富城', '黎明']
c = a + b
print(c)
# 4.2 列表重复 *
a = ['甄姬', '曹丕']
b = a*3
print(b)
# 4.3 列表分片 [start:stop:step]
# 0 1 2 3 4 5 6
a = ['刘备', '关羽', '张飞', '赵云', '马超', '黄忠', '诸葛亮']
print(a[:]) # 从开头 ~ 末尾
print(a[2:]) # 从索引2 ~ 末尾
print(a[:2]) # 从开头 ~ 索引2 (不包含索引2)
print(a[2:5]) # 从索引2 ~ 索引5 (不包含索引5)
print(a[0:6:2]) # 从索引0 ~ 索引6, 步长为2 (不包含索引6)
# 4.4 成员检测
# in
# not in
a = ['刘备', '关羽', '张飞', '赵云', '马超', '黄忠', '诸葛亮']
b = '曹操' in a # x
b = '张飞' in a # √
b = '曹操' not in a # √
print(b)
1. 遍历1
# 0 1 2 3 4 5
a = ['史珍香', '魏生津', '杜子腾', '毕云涛', '郝爽', '范建']
i = 0
while i < 6:
print(i, a[i])
i += 1
for i in range(6):
print(i, a[i])
length = len(a) # 统计 对象的长度或总数
print(length)
for i in range( len(a) ):
print(i, a[i])
)
# 遍历2
# 0 1 2 3 4 5
a = ['史珍香', '魏生津', '杜子腾', '毕云涛', '郝爽', '范建']
for i in a:
print(i, a.index(i) ) # 对象.index(值) 能获取到值的索引
a = [ [],[],[],[] ]
print(a, type(a))
a = [ ['貂蝉','西施'], ['熊大','熊二'] ]
print(a[0])
print(a[1])
print(a[0][0]) # 访问索引0下的索引为0值
print(a[1][1]) # 访问索引1下的索引为1值
print(a[1][0]) # 访问索引1下的索引为0值
# 小结: 当有多层列表时, 想要访问其中某一层列表值, 那么就用几个[]
# 3层列表中的值, 就用3个[]
# 5层列表中的值, 就用5个[]
# ...
格式: [ 变量操作 for 变量 in 列表 ]
分析:
变量: 每次获取列表中 “一个值”
变量操作: 对每一次得到的值 进行操作, 可以当做表达式
格式: [ 变量操作 for 变量 in 列表 if 条件表达式 ]
格式: [ 变量操作(true环境) if 条件表达式 else 变量操作(false环境) for 变量 in 列表 ]
式: [变量操作 for 变量1 in 列表1 for 变量2 in 列表2]
: [变量操作 for 变量1 in 列表1 for 变量2 in 列表2 if 条件]
格式: [变量操作(true环境) if 条件 else 变量操作(false环境) for 变量1 in 列表1 for 变量2 in 列表2]
一组有序的数据组合, 但不能修改数据. 元组属于不可变类型
变量名 = (值1, 值2, 值3, . )
访问元组, 通过索引来访问
修改元组,因为元组是 不可变类型, 所以无法修改元组
删除元组,因为元组是 不可变类型, 所以无法删除元组
元组也不存在插入的写法, 原因同上
合并 +
重复 *
分片 [:]
成员检测 is/not is
元组没有推导式, 但后期可以通过生成器, 来完成类似于推导式的功能
一堆由 键值对 组成的可变类型
变量名 = {键:值, 键:值, … }
键:
值: 任意类型
访问字典, 通过键 来访问
a = {'关羽':'云长', '张飞':'翼德', '刘备':'玄德'}
print(a['关羽'])
# print(a[0]) # 不再是值字典中的第一个值了, 而是键为0的值
# print(a['xxx']) # 键不存在时, 则报错
通过已有的键 来修改字典
通过已有的键 来删除字典
如果键 不存在, 则报错
in / not in
a = {'关羽':'云长', '张飞':'翼德', '刘备':'玄德'}
for i in a:
# i 获取的键
# a[i] 获取的值
print(i, a[i])
# 直接获取键 和 值
for i,j in a.items():
print(i, j)
# 单纯的遍历键
for i in a.keys():
print(i)
# 单纯的遍历值
for i in a.values():
print(i)
基本推导式
格式: { 键:值 for 键,值 in 字典.items() }
条件推导式
格式: { 键:值 for 键,值 in 字典.items() if 条件 }
多循环推导式
格式: { 键:值 for 键1,值1 in 字典1.items() for 键2,值2 in 字典2.items() }
多循环条件推导式
格式: { 键:值 for 键1,值1 in 字典1.items() for 键2,值2 in 字典2.items() if 条件}
一个值不会重复的无序序列
去重, 将一个列表转为集合, 就会自动去重
关系测试 测试两个集合交集, 差集等
变量名 = {值1, 值2, …}
变量名 = set( (值1, 值2, …) )
集 &
并集 |
差集 -
成员检测 in
添加一个值
格式1: 集合.add(值)
格式2: 集合.update( 容器 )
删除一个值
格式: 集合.remove(值)
格式: 集合.discard(值)
集合 不能通过索引来访问
集合 根本没有索引, 所以无法单独的访问
可以通过遍历来一个一个的访问
a = {'马克思','马云','马化腾','马加爵','马蓉','马航','马冬梅'}
for i in a:
print(i)
# print(a.index(i)) # 没有索引
a = {
('A1','A2','A3'),
('B1','B2','B3'),
('C1','C2','C3'),
}
print(a)
for i,j,k in a:
print(i, j, k)
# i 只获取第一列的一个值
# j 只获取第二列的一个值
# k 只获取第三列的一个值
基本推导式
格式: { 变量操作 for 变量 in 集合}
条件推导式
格式: { 变量操作 for 变量 in 集合 if 条件}
多循环推导式
格式: { 变量操作 for 变量1 in 集合1 for 变量2 in 集合1}
多循环条件推导式
格式: { 变量操作 for 变量1 in 集合1 for 变量2 in 集合1 if 条件}
一旦创建就无法再进行添加或删除的操作
变量名 = frozenset( 可迭代的对象 )
可迭代对象: 暂时理解为 字符串, 列表, 元组 …
a = frozenset( ['正太', '孟祥云', '萝莉', '小娜'] )
for i in a:
print(i)
格式:
fronzenset( 变量操作 for 变量 in 集合 )
fronzenset( 变量操作 for 变量 in 集合 if 条件)
…
普通集合: 可变类型
冰冻集合: 不可变类型
可迭代对象(iterable): 能够使用iter()的都属于可迭代对象
迭代器(iterator): 将可迭代对象一个一个进行获取
以下是常用的可迭代对象:
list
tuple
set
dict
string
range()
通过 iter() 和 next()
iter() 创建迭代器
next() 通过迭代器获取一个值
小结
迭代器与循环功能相似, 却有些不一样
迭代器 是需要用的时候, 才去拿一个值, 俗称: 懒加载
循环 是一旦开始, 就必须全部拿完
注意点:
高阶函数, 以函数作为参数时, 千万不要给函数加(), 一旦加(), 就不是送函数参数, 而是调用函数
参数为 函数
返回值为 函数
满足以上任意条件, 即可成为高阶函数
易于可读性
方便代码维护
隔离作用域
功能: 对迭代器中每一个对象, 都使用一次函数
条件限制:
可迭代对象的个数 必须与 形参的个数 一致
功能: 将可迭代对象进行排序, 生成排好的序列
参数:
iterable: 可迭代对象
key: 排序依据, 常用函数
如果没有key, 默认使用iterable的值 进行排序
key默认为 None
reverse: 升序/降序
升序: False 默认
降序: True
返回值: 排好序的可迭代对象
open(文件路径, 打开模式)
返回值: io对象
打开模式
r 只读, 指针指向开头
文件不存在, 则报错
w 只写, 指针指向开头
文件不存在, 则自动创建
a 追加, 指针指向末尾
文件不存在, 则自动创建
增强, 将具备读 和 写能力
b 二进制
io对象.read( 位数 )
文件读取, 都是通过指针来读取.
指针一般情况下, 都是指向开头
io对象.write(内容)
注意
w 模式, 会将原有内容先全部删除, 再写入内容
w 模式, 如果文件不存在, 则自动创建
io对象.open(文件路径, a)
注意:
a 模式, 会在原有内容的最后面, 进行添加内容, 不会影响原来的内容
在原有的模式上, 加强功能, 符号: +
一般情况下, 带有+的模式, 同时具备读 和 写的功能
例如:
r+
w+
a+
通常读取,写入文件时, 通过以 string 的类型进行操作
byte: 以 二进制进行存储, 以十六进制展示 (格式: \x十六进制)
如果以b模式打开, 那么在写入内容之前, 必须先转为二进制
str ==> byte 需要encode()
byte ==> str 需要decode()
为什么需要byte转换
正常人看不懂, 得到保护数据的作用
抓取的文件, 有的就是二进制
速度快
io对象.close()
所有文件一旦打开, 就会占据内存, 一天不关闭, 一天就占内存, 所以用的越久, 打开的越多, 内存就浪费的越多
close方法 主要是释放内存
因为计算机是用 二进制计算. 所以计算机只能处理数字, 而且用二进制计算也是最快的
对于汉字的底层都是二进制
ASCII 只有128
Unicode 支持大多数的语言, 比如中文, 日文, 韩文 …
缺点: 无论哪种字符 都是占4个字节, 浪费内存
UTF-8 同样支持大多数语言
优点: 英文, 数字, 占1个字节
汉字, 日文, 占3个字节 (实际根据 操作系统决定 windows 占2位 )
中国编码:
gb2312 早期的中国编码
GBK 字母数字占1位, 汉字占2位
查看当前编码
io对象.tell()
io对象.seek()
io对象.write(‘内容’)
返回值: 写入内容的长度
注意:
会清除原有的内容, 再写入新的内容
io对象.writelines( 容器 )
返回值: 无
io对象.read( n )
参数:
n 如果不填, 默认从当前指针开始, 读取到末尾
n = 1, 从当前指针开始, 向后读取1位
n = 2, 从当前指针开始, 向后读取2位
…
返回值: 读取的内容
io对象.readline(n)
参数:
n 如果不填, 从当前指针开始, 向后读取一行 (不会到下一行)
n = 1, 从当前指针开始, 向后读取1位
n = 2, 从当前指针开始, 向后读取2位
如果当前行 没有读取完毕, 下一次的readline会接着上一次继续读
如果指定n时, 已经超过当前行, 那么不会读取下一行的内容, 只会读取当前一行
返回值: 一行内容
io对象.readlines()
每一行分配一个索引, 存入列表中
第一行为索引0
第二行为索引1
…
io对象.truncate( n )
功能: 从开头向后截取n 个字节, 剩余没有被截取的将全部删除
返回值: 返回截取的长度
io对象.flush()
功能: 立马将缓冲区的内容存入文件中
返回值: 无
平时文件的写操作, 其他不会立马把内容写入文件, 只是把内容存入缓冲区
当满足以下任意条件时, 即可将缓冲区内容存入文件中
利用pycharm, 通过断点调试来查看
在以上的操作, 经常忘记close操作, 导致内存在不断的浪费.
with 会在文件操作完之后, 自动帮你关闭文件
a = open('a4.txt', 'r')
print( a.read() )
# 上面的a 没有关闭文件
with open('a4.txt','r') as file:
print(file.read())
pass
# 上面的file 已经帮你关闭的文件
在整个with的过程中, 没有close, 但是, with的代码块全部执行完时, 自动执行file.close()操作