typora的下载安装
* 这是一款火热的编辑器 是需要收费的 但是也有免费的
文件的路径
* 相对路径;不需要指引,直接可以找到相关文件
* 绝对路径:需要指引 但是不会那么容易就能找到 得一个一个看
计算机的五大组成部分详解
* 控制器:控制计算机的各个硬件的工作
* 运算器:数学运算 逻辑运算 控制器+运算器=cpu(中央处理器)
* 存储器:用于存储数据
内存:依赖电的工丢失数工作存储数据的速度非常快,但是断电就会丢失。
外存:不依赖电的工作,但是存储数据比较慢 但是可以永久的保存数据。
* 输出设备:显示屏 打印机
* 输入设备:键盘 鼠标
计算机的本质
* 计算机的本质就是一个工具 将人类想的东西用代码的方式表达出来 也可以和人类的大脑相提并论
* 计算机只能读懂0和1
计算机的三大核心硬件
* cpu:计算机的最主要的物件 相当于人的大脑中枢神经 程序想运行起来必须要有cpu的参与
* 内存;需要配合cpu 相辅相成的工作 存取速度非常的快
* 硬盘:能够长久的保存数据
环境变量配置
在cmd窗口内查找资源的时候
1.先在当前路径查找
2.如果没有 则去系统环境变量中查找
3.还没有 则会提示报错
修改环境变量之后需要使用新的cmd窗口
多版本共存:
拷贝解释器中的python.exe文件
然后给拷贝之后的文件命名(独一无二)
运行解释器的三种方式
1.cmd直接编写运行:适用于较短 临时执行的代码
2.解释器命令运行:可以编写较长的代码 并且可以长久保存
3.利用IDE工具编写并运行:IDE开发者工具 自动提示 携带各种功能插件 编写代码效率更高更快
sublime对小白不友好
vscode对小白不友好
pycharm功能强大 对小白友好
python语法注释
* 注释就是对一段代码的解释说明 相当于学习英文的时候后面有中文解释一样
* 编写注释有三种方式
方式1:在前面加上 # 也可以快捷方式 Ctrl+? # 单行注释
方式2:回车左边的按键敲连续三下
'''
多行注释
'''
方式3:回车键左边的英文输入法下+shift 连续三下
"""
多行注释
"""
python常量和变量
变量与常量就是为了让程序具备记录人记录事务状态的能力
* 变量就是记录经常改变的事务状态 年龄 薪资
* 常量就是记录固定不经常改变的事务状态 圆周率
* 变量使用的语法结构与底层原理
name=‘kevin’
变量名 赋值符号 数据值
一旦看到赋值符号就一定先看符号的右侧
先是在内存空间中申请一块内存空间存储数据值 再给数据值绑定一个变量名 以后我们需要调用的时候就可以通过变量名访问到数据值
* 注意事项
1 同一个数据值可以绑定多个变量名
2 赋值符号的右边也可能是变量名 如果是就先找这个变量名绑定的数据值
3 一个变量名同一时间只能绑定一个数据值
name='kevin'
name1=name
name2=name1
* 变量名的命名规范
1.中文是可以用作变量名的 但是不建议使用 太low了 并且容易报错
2.汉语拼音也是可以作为变量名的 但是不建议使用 太low了
3.变量名只能出现字母、数字、下划线
4.数字不能开头
5.变量名尽量做到见名知意
6.变量名不能与关键字冲突
* 变量名的命名风格
1.下划线式 python推荐使用
变量名中单词很多 彼此使用下划线隔开
name_from_mysql_db1_userinfo = 'jason'
2.驼峰体式 JS推荐使用
大驼峰
NameFromMysqlDb1Userinfo = 'jason'
小驼峰
nameFromMysqlDb1Userinfo = 'jason'
在同一个编程语言中尽量固定使用一种 不要随意切换
常量的基本使用
* 在python中没有真正意义上的常量 所有的名字都是变量,将纯大写的变量名看成是常量。
* 2.在其他编程语言中存在真正意义上的常量,绑定了关系就不能再修改。
* 常量其他特性与变量一致
数据类型
* 数据类型在日常生活中的表现形式多种多样 在程序中也是如此
* 在后期我们也要针对不同的数据采用的数据类型来表示出该数据的价值
* 我们可以通过type(数据值)/type(变量名)查看数据值的数据类型
数据类型之整型int
就是整数 对应的是 年龄 年份 人数
age= 18 year = 2022
数据类型之浮点型float
就是小数 对应的是体重 身高
height=1.75 weight=64.8
数据类型之字符串str
* 就是文本类型的数据 用引号引起来的部分就是字符串
对应的有 姓名 地址 爱好
name=‘kevin’ addr=‘上海’ hobby=‘ball’
* 定义字符串有四种方式
name = 'kevin'
name1 = "kevin"
name2 = '''kevin'''
name3 = """kevin"""
* 为什么定义字符串需要那么多种方式
我们在字符串中编写文本也可能使用到引号 为了避免冲突 有了很多方式
* 如何区分三引号是字符串还是注释
关注左侧是否含有赋值符号和变量名 如果有就是字符串 没有就是注释
数据类型之列表list
* 列表的意思就是可以存储多个数据值的类型并且可以非常方便的取
应用在存储多个数据值 并且将来可能需要单独去其中一些
代码实现:name=['jason','tony','kevin']
* 列表的文字描述
中括号括起来 内部可以存放多个数据值 数据值与数据值之间逗号隔开 数据值可以是任意数据类型
l1 = [11, 11.11, 'jason',[11, 22]]
* 2.索引取值:起始数字是从0开始
l1[索引值]
数据类型之字典dict
* 能够非常清晰精确的存储和数据值的含义
代码实现
* 字典的文字描述
大括号括起来 内部可以存放多个数据 数据的组织形式是K:V键值对
键值对与键值对之间逗号隔开
K是对V的描述性性质的信息(解释说明) 一般都是字符串类型
V是真正的数据值 可以是任意数据类型
* 2.按K取值
字典只能按K取值 因为字典是无序的 没有索引的概念
info_dict['username']
基本数据类型布尔值bool
* 用来判断事物的对错,是否可行,主要用于流程控制中
* 只有两种状态:
True 对的 真的 可行的
False 错的 假的 不可行的
* python中所有的数据都有自带的布尔值
布尔值为False的数据有:0 None ‘’ {} []
布尔值为True的数据有: 除了上述的都是True
* 存储布尔值的变量名一般推荐使用is开头
is_delete = False
is_alive = True
基本数据类型元组tuple
- 元组也被称为不可变的列表 元组内索引绑定的内存地址不能修改
- 小括号括起来 内部存放多个数据值 数据值与数据值之间逗号隔开 数据值可以是任何数据类型
- 代码实现 t1 = (11,22,‘jason’)
- 元组与列表对比
- 元组内如果只有一个数据值
在以后使用可以存放多个数据值的数据类型时 如果里面只有一个数据值 那么建议加上逗号
基本数据类型 之集合set
- 集合只能用于去重和关系运算
- 集合内数据只能是不可变类型
- 大括号括起来 内部可以存放多个数据值 数据值与数据值之间逗号隔开 数据值不是K:V键值对
- 代码实现:s1={1, 2, 3, 4, 5, 6}
- 定义空集合与字典 {} 默认是字典 set 定义空集合需要加上关键字
与用户交互
获取用户输入 input
获取用户输入 username=input('请输入您的用户名>>>:')
1 先执行赋值符号的右边input 获取用户输入
2 将输入的数据绑给变量名username
3以后的程序中可以使用变量名反复调用用户数据
- input获取到的数据都会统一处理成字符串类型
输出内部信息 print
- 括号内可以放数据值也可以放变量名 并且支持多个 逗号隔开就可以
- print自带换行符 常见的换行符有 \r\n \n(斜杠与字母组合到一起可能产生特殊的含义)
- print也可以切换结束符 print(数据,end=‘默认是\n’)
格式化输出
- 提前定义好一些内容 将未来需要使用的时候可以局部修改 比如奖状 录取通知书 合同
- 代码实现: 在现实生活中大部分情况下使用下划线提示别人填写内容 但是在程序中需要使用占位符:%s %d
单个占位符
多个占位符
有几个占位符就需要几个数据值
不同占位符的区别
流程控制理论
流程控制>>>:控制事物的执行流程
事物执行流程总共可以分为三种
1.顺序结构:从上往下依次执行 我们之前所编写的代码都属于该结构
2.分支结构:事物的执行会根据条件的不同做出不同的执行策略
3.循环结构:事物的执行会根据某个条件出现重复
在代码的世界里 很多时候可能会出现三者混合
作为小白 在学习流程控制的时候 建议做到代码和图形的结合
流程控制必备知识
- python中使用代码的缩进表示代码的从属关系 从属关系: 缩进的子代码是否执行取决于上面没有缩进的
- 并不是所有的代码都可以拥有缩进的子代码 看到if关键字
- 如果有多行子代码属于同一个父代码 那么这些子代码需要保证相同的缩进量
- python中针对缩进量没有具体的要求 但是推荐使用四个空格(windows中tab键)
- 当某一行代码需要编写子代码的时候 那么这一行代码的结尾肯定需要冒号
- 相同缩进量的代码彼此之间平起平坐 按照顺序结构依次执行
分支结构
* 单if分支结构
if 条件:条件成立后才会执行的代码块
username = input('username>>>:')
if username == 'jason':
print('老师好')
* if...else..分支结构
if条件:
条件成立之后执行的子代码
else:
条件不成立执行的子代码
username = input('username>>>:')
if username == 'jason':
print('老师好')
else:
print('去你妹的')
* if...elif...else
if 条件1:
条件1成立之后执行的子代码
elif 条件2:
条件1不成立 条件2成立执行的子代码
elif 条件3:
条件1和2都不成立 条件3成立执行的子代码
else:
上述条件都不成立 执行的子代码
ps:中间的elif可以写多个、上述子代码永远只会走一个
score = input('请输入学生成绩>>>:')
score = int(score) 将字符串的整数转换成整型的整数
if score >= 90:
print('优秀')
elif score >= 80:
print('良好')
elif score >= 70:
print('一般')
elif score >= 60:
print('及格')
else:
print('挂科 交钱重修')
* if的嵌套使用
age = 28
height = 170
weight = 110
is_beautiful = True
is_success = False
username = 'tony'
if username == 'tony':
print('tony发现目标')
if age < 30 and height > 160 and weight < 150 and is_beautiful:
print('大妹纸 手机掏出来 让我加微信')
if is_success:
print('吃饭 看电影 天黑了...')
else:
print('去你妹的 流氓!!!')
else:
print('不好意思 认错人了')
else:
print('不是tony做不出来这件事')
循环结构
* 就是想要一些代码反复的执行
while 条件:
条件成立之后执行的子代码(循环体代码)
1.先判断条件是否成立
2.如果成立则执行循环体代码
3.循环体代码执行完毕后再次回到条件判断处 判断条件是否成立
4.如果成立 则继续执行循环体代码
5.按照上述规律依次执行 直到条件不成立才会结束循环体代码的执行
break 强行结束循环
while循环体代码一旦执行到break会直接结束循环
continue 直接跳到条件判断处
while循环体代码一旦执行到continue会结束本次循环 开始下一次循环
while 条件:
循环体代码
else:
循环体代码没有被强制结束的情况下 执行完毕就会执行else子代码.
while循环补充说明
* 死循环:真正的死循环一旦执行 cpu功耗会急速上升 直到系统采取紧急措施 最好不要让cpu长时间不断运算
* 嵌套及全局标志位
一个break只能结束他所在的那一层循环
有几个while的嵌套如果想一次性结束 就要写几个break
如果不想反复写break 可以使用全局标志位
流程控制之for循环
for循环能够做到的事情while都可以做到 只不过for循环在一些场景下使用更简单
- 主要场景为:循环获取多个数据内部数据值
- 实际案例:
for 循环语法结构
for 变量名 in 待遍历的数据
for循环体代码
for循环的特点
1 擅长遍历取值
2 不需要结束条件直接结束
for循环要遍历的数据类型有 字符串 列表 元组 集合
for循环语法结构中的变量名如何命名
1.见名知意
2.如果遍历出来的数据值没有具体的含义 可以使用常用的 i j k item v
for循环体代码中如果执行到break也会直接结束整个for循环
for循环体代码中如果执行到continue也会结束当前循环直接开始下一次循环
for 变量名 in 待遍历的数据:
for循环体代码
else:
for循环体代码没有被break强制结束的情况下运行完毕之后 运行
range方法
range可以简单的理解为是帮我们产生一个内部含有多个数字数据
数据类型内置方法理论
* 在我们之前所学的每一种数据类型本身都是含有一系列的操作方法,内置方法是其中最多的(自带的功能)
* 在python中数据类型调用内置方法的统一句式为:句点符
* 'name'. 字符串内置方法
绑定字符串的变量名.字符串内置方法
str.字符串内置方法
* 数据类型的内置方法比较多 如果想要掌握 不要光靠死记硬背 需要花时间运用到代码中 熟能生巧
整型内置方法与操作
* 类型转换(将其他数据类型转换成整型)
int(其他数据类型)
浮点型可以直接转 字符串必须满足内部是纯数字才可以
* 进制数转换
十进制转其他进制
print(bin(100)) 0b1100100
print(oct(100)) 0o144
print(hex(100)) 0x64
数字的开头如果是0b则为二进制 0o则为八进制 0x则为十六进制
其他进制转十进制
print(int(0b1100100))
print(int(0o144))
print(int(0x64))
print(int("0b1100100", 2))
print(int("0o144", 8))
print(int("0x64", 16))
* python自身对数字的敏感度较低(精确度低)
python这门语言其实真的一点都不厉害 主要是因为它背后有太多大佬
如果需要精准的计算需要借助于模块numpy.....
浮点型内置方法与操作
* 类型转换 float (其他数据类型)
字符串里面可以允许出现一个小数点 其他都必须是纯数字
字符串内置方法与操作
* 类型转换 str(其他数据类型)
可以转换任意数据类型(只需要在前后加引号即可)
* 必须要掌握的方法
1 索引取值(起始位置0开始 超出范围加引号即可)
2 切片操作
3 修改切片方向
4 统计字符串首尾指定的字符
5 移除字符串首尾指定的字符
6 切割字符串指定的字符
7 字符串格式化输出
* 字符串需要了解的方法
1大小写相关
包括获取用户输入的验证码 将用户输入的验证码和当初产生的验证码统一转换或小写在比对
2 判断字符串中是否纯数字
3 替换字符串中指定的内容
4 字符串的拼接
5统计指定字符串出现的次数
6 判断字符串的开头或者结尾
7其他方法补充
列表内置方法及操作
* 类型转换list(其他数据类型)
* 能够被for循环的数据类型都可以转成列表
print(list('hello'))
print(list({'name': 'kevin', 'pwd': 123}))
print(list((1, 2, 3, 4)))
print(list({1, 2, 3, 4, 5}))
* 需要掌握的方法
11 = [111, 222, 333, 444, 555, 666, 777, 888]
1 索引取值 正负数
2 切片操作
3 间隔数 方向
4 统计列表中数据值的个数
5数据值的修改
6列表添加数据值
方式1:尾部追加数据值
方式2:任意位置插入数据值
方式3:扩展列表 合并列表
* 删除列表数据
方式1:通用的删除关键字del
方式2:remove
方式3:pop
* 排序
ss = [54, 99, 55, 76, 12, 43, 76, 88, 99, 100, 33]
* 统计列表中某个数据值出现的次数
* 颠倒列表顺序
可变类型与不可变类型
字符串在调用内置方法之后并不会修改自己 而是产生了一个新的结果 如何查看调用方法有没有新的结果 可以在调用该方法的左侧添加变量名和赋值符号
res = s1.strip('$')
列表在调用内置方法之后修改就是自身 并没有产生一个新的结果
- 可变类型:值改变 内存地址不改变
- 不可变类型:值改变 内存地址肯定变
文件操作
1.文件的概念就是操作系统暴露给用户操作硬盘的快捷方式
双击一个文件 其实是从硬盘将数据加载到内存
ctrl+s保存文件 其实是将内存中的数据刷到硬盘保存
2.代码打开文件的两种方式
方式1:f = open(文件路径,读写模式,encoding='utf8')
f.close()
方式2:with open('a.txt', 'r', encoding='utf8') as f1:
with子代码块
with上下文管理好处在于子代码运行结束自动调用close方法关闭资源
open方法的第一个参数是文件路径 并且撬棍跟一些字母的组合会产生特殊的含义导致路径查找混乱 为了解决该问题可以在字符串的路径前面加字母r
D:\a\n\t
r'D:\a\n\t'
以后涉及到路径的编写 推荐加上r
with支持一次性打开多个文件
with open() as f1,open() as f2,open() as f3:
子代码
文件读写模式
'r'只读模式:只能读不能写
1.文件路径不存在:会直接报错
with open(r'b.txt','r',encoding='utf8') as f:
print(f.read())
2.文件路径存在:正常读取文件内容
with open(r'a.txt', 'r', encoding='utf8') as f:
print(f.read())
'w'只写模式:只能写不能看
1.文件路径不存在:自动创建
with open(r'b.txt', 'w', encoding='utf8') as f:
pass
2.文件路径存在:先清空文件内容 之后再写入
with open(r'a.txt', 'w', encoding='utf8') as f:
f.write('假期综合征 赶紧要调整\n')
f.write('假期综合征 赶紧要调整\n')
f.write('假期综合征 赶紧要调整\n')
强调:换行符需要自己添加 并且在后续数据读取比对的时候也一定要注意它的存在
'a'只追加模式:文件末尾添加数据
1.文件路径不存在:自动创建
with open(r'c.txt', 'a', encoding='utf8') as f:
pass
2.文件路径存在:自动在末尾等待追加内容
with open(r'a.txt', 'a', encoding='utf8') as f:
f.write('放假七天和上班七天感觉是完全不一样的')
当我们在编写代码的时候 有些部分不知道写什么具体代码 但是也不能空着不写
这个时候可以使用关键字
pass
...
只补全语法不执行功能 本身没有任何的含义
文件操作模式
t 文本模式
默认的模式 我们上面所写的r w a其实全称是 rt wt at
1.只能操作文本文件
2.读写都是以字符为单位
3.需要指定encoding参数 如果不知道则会采用计算机默认的编码
b 二进制模式(bytes模式)
不是默认的模式 需要自己指定 rb wb ab
1.可以操作任意类型的文件
2.读写都是以bytes为单位
3.不需要指定encoding参数 因为它已经是二进制模式了 不需要编码
二进制模式与文本模式针对文件路径是否存在的情况下 规律是一样的!!!
文件诸多方法
1.read()一次性读取文件内容 并且光标停留在文件末尾 继续读取则没有内容
并且当文件内容比较多的时候 该方法还可能会造成计算机内存溢出
括号内还可以填写数字 在文本模式下 表示读取几个字符
2.for循环 一行行读取文件内容 避免内存溢出现象的产生
3.readline()一次只读一行内容
4.readlines()一次性读取文件内容 会按照行数组织成列表的一个个数据值
5.readable()判断文件是否具备读数据的能力
6.write()写入数据
7.writeable()判断文件是否具备写数据的能力
8.writelines()接收一个列表 一次性将列表中所有的数据值写入
9.flush()将内存中文件数据立刻刷到硬盘 等价于ctrl + s
文件内光标的移动
with open(r'a.txt', 'rb') as f:
print(f.read())
f.seek(0,0)
print(f.read())
f.seek(0, 0)
print(f.read())
print(f.read(2).decode('utf8'))
f.seek(-1, 2)
print(f.tell()) 返回光标距离文件开头产生的字节数
seek(offset, whence)
offset是位移量 以字节为单位
whence是模式 0 1 2
0是基于文件开头
文本和二进制模式都可以使用
1是基于当前位置
只有二进制模式可以使用
2是基于文件末尾
只有二进制模式可以使用
print(f.read(3).decode('utf8'))
函数前戏
函数相当于是工具(具有一定功能)
不用函数:修理工需要修理器件要用锤子 原地打造 每次用完就扔掉 下次用继续原地打造
用函数:修理工提前准备好工具 什么时候想用就直接拿出来使用
name_list = ['jason', 'kevin', 'oscar', 'jerry']
print(len(name_list))
突然len不准用了
count = 0
for i in name_list:
count += 1
print(count)
统计列表内数据值个数的代码需要在很多地方使用'''
相同的代码需要在不同的位置反复执行
循环相同的代码在相同的位置反复执行
函数相同的代码在不同的位置反复执行
相同的代码不是真正一模一样而是可以通过传入的数据不同而做出不同的改变
def my_len():
count = 0
for i in name_list:
count += 1
print(count)
my_len()
函数的语法结构
def 函数名(参数):
'''函数注释'''
函数体代码
return 返回值
1.def定义函数的关键字
2.函数名命名等同于变量名
3.参数可有可无 主要是在使用函数的时候规定要不要外界传数据进来
4.函数注释类似于工具说明书
5.函数体代码是整个函数的核心 主要取决于程序员的编写
6.return使用函数之后可以返回给使用者的数据 可有可无
函数的定义与调用
1.函数在定义阶段只检测语法 不执行代码
def func():
pass
2.函数在调用阶段才会执行函数体代码
func()
3.函数必须先定义后调用
4.函数定义使用关键字def函数调用使用>>>:函数名加括号
如果有参数则需要在括号内按照相应的规则传递参数
函数的分类
1.空函数:函数体代码为空 使用的pass或者...补全的
空函数主要用于项目前期的功能框架搭建
2.无参函数定义函数的时候括号内没有参数
def index():
print('from index function')
3.有参函数定义函数的时候括号内写参数 调用函数的时候括号传参数
def func(a):
print(a)
函数的返回值
1.什么是返回值:调用函数之后返回给调用者的结果
2.如何获取返回值:变量名 赋值符号 函数的调用
res = func()
先执行func函数 然后将返回值赋值给变量res
3.函数返回值的多种情况
3.1.函数体代码中没有return关键字 默认返回None
3.2.函数体代码有return 如果后面没有写任何东西还是返回None
3.3.函数体代码有return 后面写什么就返回什么
3.4.函数体代码有return并且后面有多个数据值 则自动组织成元组返回
3.5.函数体代码遇到return会立刻结束
函数的参数
形式参数:在函数定义阶段括号内填写的参数 简称'形参'
实际参数:在函数调用阶段括号内填写的参数 简称'实参'
形参与实参的关系:形参类似于变量名 在函数定义阶段可以随便写 最好见名知意
def register(name,pwd):
pass
实参类似于数据值 在函数调用阶段与形参临时绑定 函数运行结束立刻断开
函数参数
函数参数之位置参数
* 当子代码只有一行并且很简单的情况下 可以直接在冒号后编写 不用换行
* 位置形参:函数定义阶段括号内从左往右依次填写的变量名
def func(a,b,c):pass
* 位置实参:函数调用阶段括号内从左往右依次填写的数据值
func1(1, 2, 3)
越短的越简单的越靠前
越长的越复杂的越靠后
但是遇到下列的情况除外
同一个形参在调用的时候不能多次赋值
函数参数之默认参数
* 本质其实就是关键之形参
别名叫默认参数:提前就已经给了 可以不传也可以传
默认参数的定义也遵循短的简单的靠前 长的复杂的靠后
函数参数之可变长参数
| 名称 | 形参 | 实参 |
|---|---|---|
| * | *号会把溢出的位置存成元组,然后赋值其后的形参名 | *号会把值打散,字符串会变成单个字符.... |
| ** | **号会把溢出来的关键字实参存成字典,然后赋值其后的形参名 | **只能跟字典,只能将字典的key进行打散 |
由于*和**在函数的形参中使用频率很高 后面跟的变量名推荐使用
*args
**kwargs
def index(*args,**kwargs):pass
def func1(*a):
print(a)
func1() ()
func1(1) (1,)
func1(1,2) (1, 2)
def func2(b, *a):
print(a, b)
func2() 函数至少需要一个参数给到b
func2(1) () 1
func2(1, 2, 3, 4) (2, 3, 4) 1
"""
*号在形参中
用于接收多余的位置参数 组织成元组赋值给*号后面的变量名
"""
def func3(**k):
print(k)
func3() {}
func3(a=1) {'a': 1}
func3(a=1, b=2, c=3) {'a': 1, 'b': 2, 'c': 3}
def func4(a, **k):
print(a, k)
func4() 函数至少需要一个参数给到a
func4(a=1) 1 {}
func4(a=1, b=2, c=3) 1 {'b': 2, 'c': 3}
func4(a=1, b=2, c=3, x='jason', y='kevin') 1 {'b': 2, 'c': 3, 'x': 'jason', 'y': 'kevin'}
**号在形参中
用于接收多余的关键字参数 组织成字典的形式赋值给**号后面的变量名
def func5(*a, **k):
print(a, k)
func5() () {}
func5(1, 2, 3) (1, 2, 3) {}
func5(a=1, b=2, c=3) () {'a': 1, 'b': 2, 'c': 3}
func5(1, 2, 3, a=1, b=2, c=3) (1, 2, 3) {'a': 1, 'b': 2, 'c': 3}
def func5(n, *a, **k):
print(a, k)
func5() 函数至少需要一个参数给到n
func5(1, 2, 3) (2, 3) {}
func5(111,a=1, b=2, c=3) () {'a': 1, 'b': 2, 'c': 3}
func5(n=111,a=1, b=2, c=3) () {'a': 1, 'b': 2, 'c': 3}
func5(a=1, b=2, c=3, n=111) () {'a': 1, 'b': 2, 'c': 3}
func5(1, 2, 3, a=1, b=2, c=3) (2, 3) {'a': 1, 'b': 2, 'c': 3}
函数参数之可变长实参
def index(a, b, c):
print(a, b, c)
l1 = [11, 22, 33]
t1 = (33, 22, 11)
s1 = 'tom'
se = {123, 321, 222}
d1 = {'username': 'jason', 'pwd': 123, 'age': 18}
将列表中三个数据值取出来传给函数的三个形参
index(l1[0], l1[1], l1[2])
index(*l1) # index(11, 22, 33)
index(*t1) # index(33, 22, 11)
index(*s1) # index('t','o','m')
index(*se) # index(321 123 222)
index(*d1) # index('username','pwd','age')
*在实参中
类似于for循环 将所有循环遍历出来的数据按照位置参数一次性传给函数
def index(username, pwd, age):
print(username, pwd, age)
d1 = {'username': 'jason', 'pwd': 123, 'age': 18}
index(username=d1.get('username'), pwd=d1.get('pwd'), age=d1.get('age'))
index(**d1) # index(username='jason',pwd=123,age=18)
**在实参中
将字典打散成关键字参数的形式传递给函数
def index(*args, **kwargs):
print(args) (11, 22, 33, 44)
print(kwargs) {}
index(*[11, 22, 33, 44]) index(11, 22, 33, 44)
index(*(11, 22, 33, 44)) index(11, 22, 33, 44)
名称空间
名称空间就是用来存储变量名与数据值绑定关系的地方(我们也可以简单的理解为就是存储变量名的地方)
* 内置空间:解释器运行自动产生 里面包含了很多名字
内置名称空间:python解释器启动则创建 关闭则销毁
内置名称空间:解释器级别的全局有效
* 全局名称空间:Py文件存放文件级别的名字
全局名称空间:py文件执行则创建 运行结束则销毁
全局名称空间:py文件级别的全局有效
* 局部名称空间:函数体代码运行\类体代码运行 产生的空间
局部名称空间:函数体代码运行创建 函数体代码结束则销毁
局部名称空间:函数体代码内有效
名字查找顺序
涉及到名字的查找 一定要先搞明白自己在哪个空间
1.当我们在局部名称空间中的时候
局部名称空间 >>> 全局名称空间 >>> 内置名称空间
2.当我们在全局名称空间中的时候
全局名称空间 >>> 内置名称空间
其实名字的查找顺序是可以打破的
查找顺序案例
- 相互独立的局部名称空间默认不能够互相访问
- 局部名称空间嵌套 先从自己的局部名称空间查找 之后由内而外依次查找 函数体代码中名字的查找顺序在函数定义阶段就已经固定死了
global与nonlocal
-
局部名称空间直接修改全局名称空间中的数据 +
-
内层局部名称空间修改外层局部名称空间中的数据
函数名的多种用法
函数名其实也是绑定的一块内存地址 只不过该地址里面存放的不是数据值而是一段代码 函数名加括号找到相应代码并执行
当成变量名赋值
def index():pass
res=index
res()
当成函数的参数
def index():
print('from index')
def func(a):
print(a)
a()
func(index)
当成函数的返回值
def index():
print('from index')
def func():
print('from func')
return index
res = func()
print(res)
res()
def index()
print('from index')
def func():
print('from func')
return func
res = index()
print(res)
res()
可以当成容器类型的数据
def register():
print('注册功能')
def login():
print('登录功能')
def withdraw():
print('提现功能')
def transfer():
print('转账功能')
def shopping():
print('购物功能')
# 定义功能编号与功能的对应关系
func_dict = {
'1': register,
'2': login,
'3': withdraw,
'4': transfer,
'5': shopping
}
while True:
print("""
1.注册功能
2.登录功能
3.提现功能
4.转账功能
5.购物功能
""")
choice = input('>>>:').strip()
if choice in func_dict:
func_name = func_dict.get(choice)
func_name()
else:
print('功能编号不存在')
闭包函数
定义在函数内部的函数 并且用到了外部函数名称空间中的名字
1 定义在函数内部
2 用到外部函数名称空间中的名字
def index():
name = 'jason'
def inner():
print(name)
闭包函数实际应用就是另外一种给函数体代码传参的方式
方式1 :代码缺什么变量名形参里里面就补什么变量名
方式2:闭包函数
装饰器简介
概念:在不改变被装饰对象原代码和调用方式的情况下给装饰对象添加新功能
本质:并不是一门新的技术 而是由函数参数 名称空间 函数名多种用法 闭包函数组合到一起的结果
口诀:对修改封闭 对扩展开放
import time
print(time.time()) 时间戳(距离1970-01-01 00:00:00所经历的秒数)
time.sleep(3)
print('睡醒了 干饭')
装饰器推导流程
import time
def index():
time.sleep(3)
print('from index')
def home():
time.sleep(1)
print('from home')
- 直接在调用index函数的前后添加代码
- 2.index调用的地方较多 代码不可能反复拷贝>>>:相同的代码需要在不同的位置反复执行>>>:函数
- 3.函数体代码写死了 只能统计index的执行时间 如何才能做到统计更多的函数运行时间 直接传参变换统计的函数
- 4.虽然实现了一定的兼容性 但是并不符合装饰器的特征 第一种传参不写 只能考虑闭包
- 5.调用方式还是不对 如何变形>>>:变量名赋值绑定
- 6.上述装饰器只能装饰无参函数 兼容性太差
- 7.被装饰的函数不知道有没有参数以及有几个参数 如何兼容
- 8.如果被装饰的函数有返回值
装饰器模板
def outer(func):
def inner(*args, **kwargs):
# 执行被装饰对象之前可以做的额外操作
res = func(*args, **kwargs)
# 执行被装饰对象之后可以做的额外操作
return res
return inner
装饰器语法糖
语法糖会自动将下面紧挨着的函数名当做第一个参数自动传给@函数调用
ef outer(func_name):
def inner(*args, **kwargs):
print('执行被装饰对象之前可以做的额外操作')
res = func_name(*args, **kwargs)
print('执行被装饰对象之后可以做的额外操作')
return res
return inner
@outer # func = outer(func)
def func():
print('from func')
return 'func'
@outer # index = outer(index)
def index():
print('from index')
return 'index'
func()
index()
多层语法糖
多层语法糖 加载顺序由下往上
每次执行之后如果上面还有语法糖 则直接将返回值函数名传给上面的语法糖
如果上面没有语法糖了 则变形 index = outter1(wrapper2)
def outter1(func1):
print('加载了outter1')
def wrapper1(*args, **kwargs):
print('执行了wrapper1')
res1 = func1(*args, **kwargs)
return res1
return wrapper1
def outter2(func2):
print('加载了outter2')
def wrapper2(*args, **kwargs):
print('执行了wrapper2')
res2 = func2(*args, **kwargs)
return res2
return wrapper2
def outter3(func3):
print('加载了outter3')
def wrapper3(*args, **kwargs):
print('执行了wrapper3')
res3 = func3(*args, **kwargs)
return res3
return wrapper3
@outter1
@outter2
@outter3
def index():
print('from index')
有参装饰器
def outer(mode):
def login_auth(func_name):
def inner(*args, **kwargs):
username = input('username>>>:').strip()
password = input('password>>>:').strip()
if mode == '1':
print('数据直接写死')
elif mode == '2':
print('数据来源于文本文件')
elif mode == '3':
print('数据来源于字典')
elif mode == '4':
print('数据来源于MySQL')
return inner
return login_auth
当装饰器中需要额外的参数时>>>:有参装饰器
函数名加括号执行优先级最高 有参装饰器的情况
先看函数名加括号的执行
然后再是语法糖的操作
@outer('1')
def index():
print('from index')
index()
@outer('2')
def func():
print('from func')
func()
装饰器模板
* 最常用的无参装饰器
def outer(func_name):
def inner(*args, **kwargs):
res = func_name(*args, **kwargs)
return res
return inner
@outer
def index():
pass
* 不常用的有参装饰器
def outer_plus(mode):
def outer(func_name):
def inner(*args, **kwargs):
res = func_name(*args, **kwargs)
return res
return inner
return outer
@outer_plus('MySQL')
def func():
pass
装饰器修复技术
from functools import wraps
pass
@wraps(func_name) # 仅仅是为了让装饰器的效果更加逼真 平时可以不写
递归函数
* 函数的递归调用: 函数直接或者间接调用了函数本身
1 直接调用
def index():
print('from index')
index()
index()
2 间接
def index():
print('from index')
func()
def func():
print('from func')
index()
func()
最大的递归深度 python解释器添加的安全措施
count = 0
def index():
globl count
count +=1
print(count)
index()
index()
官网提供的最大递归深度为1000 我们在测试的时候可能会出现996 997 998
* 递归函数
直接或者间接调用自己
每次调用都比上一次简单 并且需要一个明确的结束条件
get_age(5) = get_age(4) + 2
get_age(4) = get_age(3) + 2
get_age(3) = get_age(2) + 2
get_age(2) = get_age(1) + 2
get_age(1) = 18
def get_age(n):
if n == 1:
return 18
return get_age(n-1) + 2
res = get_age(5)
print(res)
递归函数真正的应用场景
递推:一次次寻找答案直到找到答案
回溯:根据最终答案在向回推导找到答案
算法简介之二分法
* 什么是算法:算法就是解决问题的有效方法 不是所有的算法都很高效
* 算法应用场景:
推荐算法 像抖音推送 淘宝商品推送
成像算法 AI相关
算法几乎是覆盖了我们日常生活中的方方面面
* 二分法:是算法中最简单的算法 甚至都称不上是算法
* 二分法使用要求:待查找的数据集必须有序
* 二分法的缺陷:针对开头结尾数据 查找效率很低
* 常见算法的原理以及伪代码
二分法 冒泡 快拍 插入 桶排 数据结构(链表 约瑟夫问题 如何链表是否成环)
l1 = [12, 21, 32, 43, 56, 76, 87, 98, 123, 321, 453, 565, 678, 754, 812, 987, 1001, 1232]
查找列表中某个数据值
方式1:for循环 次数较多
方式2:二分法 不断的对数据集做二分切割
代码实现二分法
定义我们想要查找的数据值
target_num = 987
def get_middle(l1, target_num):
# 添加一个结束条件
if len(l1) == 0:
print('很抱歉 没找到')
return
# 1.获取列表中间索引值
middle_index = len(l1) // 2
# 2.比较目标数据值与中间索引值的大小
if target_num > l1[middle_index]:
# 切片保留列表右边一半
right_l1 = l1[middle_index + 1:]
print(right_l1)
# 针对右边一半的列表继续二分并判断 >>>: 感觉要用递归函数
return get_middle(right_l1, target_num)
elif target_num < l1[middle_index]:
# 切片保留列表左边一半
left_l1 = l1[:middle_index]
print(left_l1)
# 针对左边一半的列表继续二分并判断 >>>: 感觉要用递归函数
return get_middle(left_l1, target_num)
else:
print('恭喜你 找到了!!!')
get_middle(l1, 987)
get_middle(l1, 2000)
get_middle(l1, 12)
三元表达式
简化步骤:代码简单并且只有一行 那么可以直接在冒号后面编写
name=‘jason’
if name == 'jason':print(‘老师’)
else:print('学生')
三元表达式
res='老师'if name == ‘jason’slse‘学生’
print(res)
数据值1 if 条件 else 数据值2
条件成立则使用数据值1 条件不成立则使用数据值2
当结果是二选一的情况下 使用三元表达式较为简便
并且不推荐多个三元表达式嵌套
各种生成式
name_list = ['jason', 'kevin', 'oscar', 'tony', 'jerry']
给列表中所有人名的后面加上_NB的后缀
- 字典生成式
- 集合生成式
- 元组生成式>>>:没有元组生成式 下列的结果是生成器(后面讲)
匿名函数
没有名字的函数 需要使用关键字lambda
结构:lambda 形参:返回值
使用场景:lambda a,b:a+b
匿名函数一般不单独使用需要配合其他函数一起用
常见内置函数
映射 map()
l1 = [1, 2, 3, 4, 5]
res = map(lambda x:x+1, l1)
print(list(res)) [2, 3, 4, 5, 6]
- 查询最大值使用的是max()函数,查询最小值使用的是min()函数
* reduce 传多个值 返回一个值
reduce()函数会对参数序列中元素进行累积。
函数将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用 function 函数运算,最后得到一个结果。
Python3.x reduce() 已经被移到 functools 模块里,如果我们要使用,需要引入 functools 模块来调用 reduce() 函数:
from functools import reduce
重要内置函数
zip()
从参数中的多个迭代器取元素组合成一个新的迭代器;
返回:返回一个zip对象,其内部元素为元组;可以转化为列表或元组;
传入参数: 元组、列表、字典等迭代器
filter()
作用为筛选,接受一个筛选函数和一个序列;
筛选函数作用于序列的每一个元素,根据筛选函数的返回值(True或者False)决定该序列中的该元素是否保留。
语法:filter(function, iterable)
参数
function – 判断函数
iterable – 可迭代对象
返回值返回一个迭代器对象Iterator;
sorted()
sorted是python的内置函数,并不是可变对象(列表、字典)的特有方法,sorted()函数需要一个参数(参数可以是列表、字典、元组、字符串),无论传递什么参数,都将返回一个以列表为容器的返回值,如果是字典将返回键的列表。
常见内置函数
abs() 绝对值
all() 所有的数据值对应的布尔值为True结果才是True 否则返回False
any()所有的数据值对应的布尔值有一个为True结果就是True 否则返回False
bin()oct()hex()十进制转其他进制
int() 类型转换 其他进制转十进制
bytes() 转换成bytes类型
callable() 判断名字是否可以加括号调用
chr() ord() 基于ASCII码表左庶子与字母的转换
dir() 获取对象内部可以通过句点符获取的数据
divmod() 获取除法之后的整数和余数
enumerate() 枚举
hash() 返回一串随机的数字(哈希值)
help() 查看帮助信息
isinstance() 判断某个数据是否属于某个数据类型
pow() 幂指数
round() 大致:四舍五入
可迭代对象:字符串 列表 字典 元组 集合 文件对象(本身就是迭代器对象)
不是可迭代对象: 整型 浮点型 布尔值 函数名
可迭代对象能够支持for循环取值
可迭代对象
1.可迭代对象
对象内置有__iter__方法的都称为可迭代对象
1.内置方法 通过点的方式能够调用的方法
2.__iter__ 双下iter方法
2.可迭代对象的范围
不是可迭代对象
int float bool 函数对象
是可迭代对象
str list dict tuple set 文件对象
3.可迭代的含义
迭代:更新换代(每次更新都必须依赖上一次的结果)
手机app更新
可迭代在python中可以理解为是否支持for循环
迭代器对象
1.迭代器对象
是由可迭代对象调用__iter__方法产生的
迭代器对象判断的本质是看是否内置有__iter__和__next__
2.迭代器对象的作用
提供了一种不依赖于索引取值的方式
正因为有迭代器的存在 我们的字典 集合才能够被for循环
3.迭代器对象实操
s1 = 'hello' 可迭代对象
res = s1.__iter__() 迭代器对象
print(res.__next__()) 迭代取值 for循环的本质
一旦__next__取不到值 会直接报错
4.注意事项
可迭代对象调用__iter__会成为迭代器对象 迭代器对象如果还调用__iter__不会有任何变化 还是迭代器对象本身
for循环的本质
for 变量名 in 可迭代对象:
循环体代码
1.先将in后面的数据调用__iter__转变成迭代器对象
2.依次让迭代器对象调用__next__取值
3.一旦__next__取不到值报错 for循环会自动捕获并处理
异常捕获/处理
1.异常
异常就是代码运行报错 行业俗语叫bug
代码运行中一旦遇到异常会直接结束整个程序的运行 我们在编写代码的过程中药尽可能避免
2.异常分类
语法错误
不允许出现 一旦出现立刻改正 否则提桶跑路
逻辑错误
允许出现的 因为它一眼发现不了 代码运行之后才可能会出现
3.异常结构
错误位置
错误类型
错误详情
os模块
os模块主要和当前的程序所在的操作系统打交道
import os
* 创建目录
os.mkdir(r'aaa') 创建单级文件夹
os.mkdir(r'bbb/ccc/ddd') 无法创建多级文件夹 会报错
os.makedirs(r'bbb/ccc/ddd') 可以创建多级文件夹
os.makedirs(r'ccc') 同时也是支持单个文件夹的创建
* 删除目录
os.rmdir(r'aaa') 可以删除单级文件夹
os.rmdir(r'bbb/ccc/ddd') 无法删除多级文件夹会报错
os.removedirs(r'ccc') 对于有数据的文件夹也是无法删除的
os.removdirs(r'bbb/ccc/ddd')从内到外的开始删除 直到有数据的文件夹
- 列举指定路径下文件名称 print(os.listlib())当前所在的文件夹 print(os.listlib(r'c:\'))电脑上c盘的路径
* 重命名文件 删除文件
os.rename(r'yqb.txt',r'tq.txt')
将文件yqb修改为tq
os.remove(r'tq.txt')
将tq.txt文件删除
* 获取当前所在路径
print(os.getcwd()) 当前所在路径
os.chdir(r'...') 改变当前文件夹到其他文件夹
os.mkdir(r'hahah') 创建了‘hahah’文件夹
print(os.geicwd())
- 与程序启动文件相关 print(os.path.abspath(file)) 获取文件的绝对路径 print(os.path.dirname(file)) 获取文件所在目录路径
* 判断路径是否存在
print(os.path.exists(r'eee'))
print(os.path.exists(r'aaa'))
print(os.path.isdir(r'eee'))
print(os.path.isfile(r'eee'))
* 拼接路径
relative_path='eee'
absolute_path=r'D:\Users\余其兵\6\day7\too'
print(absolute_path+relative_path)
涉及路径拼接不要使用加号
res=os.path.join(relative_path,absolute_path)
print(res)
join会自动识别当前所在操作系统并切换正确的分隔符
- 获取文件大小写 print(os.path.getsize(r'zuoye.py')) print(os.path.getsize(r'eee')) 用bytes表示
sys模块
sys模块主要喝python解释器打交道
import sys
print(sys.path)
print(sys.platfrom)
print(sys.version)
json模块
* json模块==序列化模块
不同编程语言之间数据监护必备的模块
* json格式的数据应该是基于网络传输二进制 在python中只有字符串可以调用encode方法转成二进制数据 所以json格式的数据也是属于字符串。
* json格式的数据有一个非常明显的特征首先肯定是字符串 其次引号是标志性的双引号
dumps()
d={'name':'yqb','pwd':'123'}
import json
res=json.dumps(d)
print(res,type(res))
序列化 将其他数据类型转换成json格式化字符串
dumps()
res1=json.loads(res)
print(res1,type(res1))
反序列化 将json格式化字符串转换成对应编程语言中的数据类型
dump() 将其他数据类型以json格式字符串写入文件
load() 将文件中json格式字符串读取出来并转换成对应的数据类型
d={'name':'yqb','pwd':'123'}
import json
with open(r'b.txt','w',encoding='utf8')as f:
json.dump(d,f)
with open(r'b.txt','r',encoding='utf8')as f:
res=json.load(f)
print(res,type(res))