第一章 计算机基础
1.1 硬件
计算机基本的硬件由:CPU / 内存 / 主板 / 硬盘 / 网卡 / 显卡 等组成,只有硬件但硬件之间无法进行交流和通信。
1.2 操作系统
作用:操作系统用于协同或控制硬件之间进行工作
常见的操作系统
- windows,丰富的图形化界面、收费、大量工具、适用于个人办公
- XP
- win7
- win10
- window server
- linux,性能好、占用资源少、适用于做服务器
- centos:公司线上一般用
- ubuntu
- redhat
- mac,人性化交互好、好看好用、适用于个人使用
1.3 解释器或编译器
编程语言的开发者写的一个工具,将用户写的代码转换成010101交给操作系统去执行。
1.3.1 编译型语言和解释性语言
- 编译型语言:代码写完后,编译器将其变成成另外一个文件,然后交给计算机执行
- 常见的编译型语言:C,C++,Java,C#,Go等
- 解释型语言:写完代码交给解释器,解释器会从上到下一行行代码执行:边解释边执行(实时翻译)
- 常见的解释型语言:Python,PHP,ruby等
1.4 软件(应用程序)
软件又称为应用程序,就是我们在电脑上使用的工具,类似于:记事本 / 图片查看 / 游戏
1.5 进制
对于计算机而言无论是文件存储 / 网络传输输入本质上都是:二进制(010101010101),如:电脑上存储视频/图片/文件都是二进制; QQ/微信聊天发送的表情/文字/语言/视频 也全部都是二进制。
进制:
- 2进制,计算机内部。
- 8进制
- 10进制,人来进行使用一般情况下计算机可以获取10进制,然后再内部会自动转换成二进制并操作。
- 16进制,一般用于表示二进制(用更短的内容表示更多的数据),一版是:\x 开头。
二进制 | 八进制 | 十进制 | 十六进制 |
---|---|---|---|
0 | 0 | 0 | 0 |
1 | 1 | 1 | 1 |
10 | 2 | 2 | 2 |
11 | 3 | 3 | 3 |
100 | 4 | 4 | 4 |
101 | 5 | 5 | 5 |
110 | 6 | 6 | 6 |
111 | 7 | 7 | 7 |
1000 | 10 | 8 | 8 |
1001 | 11 | 9 | 9 |
1010 | 12 | 10 | A |
1011 | 13 | 11 | B |
1100 | 14 | 12 | C |
1101 | 15 | 13 | D |
1110 | 16 | 14 | E |
1111 | 17 | 15 | F |
10000 | 20 | 16 | 10 |
第二章 Python入门
2.1 环境的安装
-
解释器
- 设置环境变量(注意设置系统的环境变量)
- 用途:方便在命令行(终端)执行可执行程序,将可执行程序所在的目录添加到环境变量,那么以后无需再输入路径
- 多环境共存
- python2.7
- python3.6
- 开发工具:pycharm
- pycharm变更解释器
2.2 编码
2.2.1 编码基础
- ascii
- 1字节,8位
- 只包含英文和符号
- 占用内存少
- unicode(万国码)
- 4字节,32位
- 包含所有的语言
- 占用内存大
- 种类:
- ecs2
- ecs4
- 注:现在通常是用ecs4
- utf-8(对unicode的压缩)
- 1-4字节,8的倍数位(8、16、24、32位)
- 包含所有的语言
- 优化了unicode占用内存太大的问题
- 中文用3个字节表示
- utf-16
- 注:电脑上用unicode保存,其实是用的utf-16保存的
- gbk
- 已全包含中文
- 中文用2个字节表示
- gb2312(gbk的升级版)
- 已全包含中文
- 中文用2个字节表示
2.2.2 python编码相关
- python解释器默认编码(python2与python3的区别一)
- python2 解释器默认编码:ascii
- python3 解释器默认编码:utf-8
- 指定python解释器使用utf-8
- 在文件头添加:#-- coding:utf-8 - -,则完成指定
- 注:建议无论使用python2或python3执行,均添加
# -*- coding:utf-8 -*-
注意:对于操作文件时,要按照:以什么编写写入,就要用什么编码去打开。
- 单位转化
- 常用单位:位(bit),字节(byte),KB,兆(MB),GB.TB等
- 常见转化:
- 8 bit = 1 byte
- 1024 byte = 1 KB
- 1024 KB = 1 MB
- 1024 MB = 1 GB
- 1024 GB = 1 TB
2.3 输入和输出
2.3.1 输入
input("请输入你的姓名:")
input输入得到的内容永远是字符串
- python版本的区别(python2与python3的区别二)
- python2:name=raw_input('请输入姓名')
- python3:name=input('请输入你的姓名')
2.3.2 输出
- print(你想要输出的东西)
- python版本的区别(python2与python3的区别三)
- python2:print "你好"
- python3:print("你好")
- 注:python2.7以上两种均可以
2.4 变量
- 要求
- 变量名只能包含字母,数字和下划线
- 变量名不能用数字开头
- 变量名不能是python的关键字
- 建议
- 见名知意:name='alex' 或者age=18
- 名字太长用下划线:lily_dad='tom'
- 补充:LilyDad="tom" (驼峰式命名)
-
问:为什么要有变量?
答:为某个值创建一个“外号”,以后在使用时候通过此外号就可以直接调用。
-
示例:
-
变量
name = 'alex'
-
全局变量
NAME = "oldboy"
-
函数
def func_list(): pass
-
常量
不允许修改的值,Python中执行约定。
-
2.5 注释
-
单行注释
- 行头加#
- 例:# 用户 密码
-
多行注释
使用三引号
-
例:"""
用户
密码
"""
2.6 条件语句
2.6.1 基本格式
-
初级条件语句(if语句)
#基本格式: if 条件: print('结论一') else: print('结论二')
-
elif语句
#基本格式: if 条件一: print('结论一') elif 条件二: #elif的数量不限制 print('结论二') elif 条件三: print('结论三') else: print('结论四')
-
最简单(只有一个if)
#基本格式: if 条件: print('结论')
-
if条件语句嵌套
#10086示例 message = """欢迎致电10086 1.话费查询; 2.流量服务; 3.业务办理; 4.人工服务""" print(message) index = input('请输入你要选择的服务:') index = int(index) if index==1: print('话费查询') elif index == 2: print('流量服务') elif index == 3: content = """业务办理 1. 修改密码; 2. 更改套餐; 3. 停机;""" print(content) value = input('请输入要办理的业务:') value = int(value) if value == 1: print('修改密码') elif value == 2: print('更改套餐') elif value == 3: print('停机') else: print('错误') elif index == 4: print('人工服务') else: print('输入错误')
2.6.2 三元运算(三目运算)
- 用途:用于简单的if条件语句
- 基本结构
v = 前面 if 条件 else 后面
#如果条件为真,v = 前面,否则,v = 后面
"""
相当于
if 条件:
v = 前面
else:
v = 后面
"""
# 让用户输入值,如果值是整数,则转换成整数,否则赋值为None
data = input('>>>') value = int(data) if data.isdecimal() else None
- 注意:现阶段先不要直接使用三元运算,先做出来,再思考如何简化
2.7 循环语句
2.7.1 while循环
- 基本循环结构
while True:
print('你想要循环的东西')
- while后面加条件
while 1>0 and 1<2:
print('你好')
- 关键词
-
pass:空代码,什么都不干
count = 1 while count <=10: if count == 7: pass #跳过,不打印 else: print(count) count = count + 1
-
break:终止(当前循环)
while True: print('666') while True: print('888') break #终止第二个while循环 break #终止第一个while循环
-
continue:继续
count = 1 while count <=10: if count == 7: count = count + 1 continue #不再继续往下走,而是回到while条件的位置 print(count) count = count + 1
- while-else结构
count = 1
while count <=10:
print(count)
count = count + 1
else: #不再满足while后的条件时,或者条件=False时,触发
print(666)
2.7.2 for循环
- 使用方式
name = 'alex'
for item in name:
print(item)
- 注意
- 用循环打印字符串的每个元素:for > while
- 死循环:while > for
- for和while的应用场景:有穷尽优先用for,无穷尽用while
- for循环 + range
#示例:打印1 - 10
# range(0,10):[1,2,3,4,5,6,7,8,9]
for i in range(0,11):
print(i)
-
range / xrange(python2与python3的区别六)
- python2:
- xrange:不会在内存中立即创建,而是在循环时,边循环边创建
- range:在内存立即把所有的值创建
- python3:
- 只有range,相当于python2中的xrange
- range:不会在内存中立即创建,而是在循环时,边循环边创建
- python2:
2.8 运算符
-
算数运算
#示例:打印1-100之间的奇数 count = 1 while count <= 100: val = count % 2 if val == 1: print(count) count = count + 1
-
赋值运算
count += 1等价于count = count + 1
-
逻辑运算(and,or,not)
一般情况,用于判断(布尔类型)
-
二般情况,用于取值
-
or value = x or y
如果x转化为布尔类型为False,则value = y
如果x转化为布尔类型为True,则value = x
如果有多个or条件,则从左到右依次进行上述流程
-
and value = x and y
如果x转化为布尔类型为False,则value = x
如果x转化为布尔类型为True,则value = y
如果有多个and条件,则从左到右依次进行上述流程
同时有and和or条件,有括号的先算括号,没有就先算and再算or
优先级:( ) > not > and > or
-
-
补充
- in 在里面
- not in 不在里面
- 优先级补充(>优先于not)
第三章 数据类型
3.1 整型(int)
-
数字表示(python2与python3的区别四)
-
python2
64位机器,范围-2^63~2^63-1
-
超出上述范围,python自动转化为long(长整型)
注:long(长整型)数字末尾有一个L
-
python3
- 所有整型都是int,没有long(长整型)
-
-
整型除法(python2与python3的区别五)
- python2:只能保留整数位
- python3:可以保留所有内容
3.2 布尔(bool)
- 布尔值就是用于表示真假
- 布尔值:True和False
- 其他类型转换成布尔值:
- 整型转换为布尔值
- 0转换后是False,其他转换为True
- 字符串转换为布尔值
- ""转换后是False,其他转换为True
- 列表转换为布尔值
- []转换后是False,其他转换为True
- 元组转换为布尔值
- ()转换后是False,其他转换为True
- 字典转换为布尔值
- {}转换后是False,其他转换为True
- 集合转换为布尔值
- set()转换后是False,其他转换为True
- None转换为布尔值:False
- 整型转换为布尔值
3.3 字符串(str)
字符串是写代码中最常见的,python内存中的字符串是按照:unicode编码存储
字符串是不可变类型
str(字符串类型)的区别(python2与python3的最大区别)(区别十,优先写这个)
- python2:
- str类型,相当于python3中的字节类型,utf-8/gbk等其他编码
- unicode类型,相当于python3中的字符串类型,unicode编码
- python2中没有字节类型
- python3:
- str类型,字符串类型,unicode编码
- python3中没有unicode类型
字符串自己的方法:
-
upper/lower:字母大小写转换
- upper:字母小写转换为大写
- lower:字母大写转换为小写
v1 = 'alex'
v2 = v1.upper()
print(v2) #'ALEX'
v3 = v2.lower()
print(v3) #'alex'
- isdigit:判断字符串是否为数字
v1 = 'alex'
date1 = v1.isdigit()
print(date1) #False
v2 = '666'
date2 = v2.isdigit()
print(date2) #True
- strip/rstrip/lstrip:去除空格
- strip:去除左右两边的空格
- rstrip:去除右边的空格
- lstrip:去除左边的空格
v = ' alex '
date1 = v1.strip()
print(date1) #'alex'
date2 = v.rstrip()
print(date2) #' alex'
date3 = v.lstrip()
print(date3) #'alex '
- replace:替换
v = '今天我要吃炒饭炒饭炒饭'
date1 = v.replace('炒饭','烤鸭') #替换所有炒饭
print(date1) #'今天我要吃烤鸭烤鸭烤鸭'
date2 = v.replace('炒饭','烤鸭',1) #只替换第1个炒饭
print(date2) #'今天我要吃烤鸭炒饭炒饭'
- split/rsplit:切割
- split:从左到右切割
- rsplit:从右到左切割
v = '今天我要吃炒饭、烧鸡、烤鸭'
date1 = v.split('、') #从左到右,切割所有的顿号
print(date1) #['今天我要吃炒饭','烧鸡','烤鸭']
date2 = v.split('、',1) #从左到右,切割第一个顿号
print(date2) #['今天我要吃炒饭','烧鸡、烤鸭']
date2 = v.rsplit('、',1) #从右到左,切割第一个顿号
print(date2) #['今天我要吃炒饭、烧鸡','烤鸭']
- startswith/endswith:判断是否已什么开头/结尾
- startswith:判断是否已什么开头
- endswith:判断是否已什么结尾
v = 'alex'
date1 = v.startswith('al')
print(date1) #True
date2 = v.endswith('ex')
print(date2) #True
- format:字符串格式化
date = '他叫{0},今年{1}'.format('张三',22)
print(date) #'他叫张三,今年22'
- encode:将unicode存储转换为其他编码存储
name = '张三' #解释器读取到内存后,用unicode存储
date1 = name.encode('utf-8') #将unicode存储转换为utf-8存储
date2 = name.encode('gbk') #将unicode存储转换为gbk存储
- join:循环每个元素,并在元素和元素之间加入加入连接符
v = 'alex'
date = "_".join(v) #循环每个元素,并在元素和元素之间加入"_"
print(date) #'a_l_e_x'
字符串格式化总结:
-
%s
# 示例一:特别注意:最后的右括号前面必须有逗号(,) msg = '我是%s,年龄%s'%('alex',19,) # 元组 # 示例二: msg = '我是%(name)s,年龄%(age)s'%{'name':'alex','age':19} # 字典 # 示例三:要想打印%,必须写两个%,即%% template = "%s现在的手机电量是100%%"%('alex',)
-
format
# 示例一: msg = '我是{0},年龄{1}'.format('alex',19) # 相当于 msg = '我是{0},年龄{1}'.format(*('alex',19,)) # 示例二: msg = '我是{name},年龄{age}'.format(name = 'alex',age = 18) # 相当于 msg = '我是{name},年龄{age}'.format(**{'name':'alex','age':18})
3.4 列表(list)
想要表示多个事物,可以用列表
列表是可变类型
列表自己的方法:
- append:追加
v = ['张三','李四','王五']
v.append(666)
print(v) #['张三','李四','王五',666]
- insert:插入
v = ['张三','李四','王五']
v.insert(1,666)
print(v) #['张三',666,'李四','王五']
- remove:删除(指定元素)
v = ['张三','李四','王五']
v.remove('李四')
print(v) #['张三','王五']
- pop:删除(索引位置的元素)
v = ['张三','李四','王五']
v.pop(o)
print(v) #['李四','王五']
- clear:删除全部内容
v = ['张三','李四','王五']
v.clear(o)
print(v) #[]
- extend:循环加入
v = ['张三','李四','王五']
v1 = [1,2,3]
v.extend(v1) #把v1中的元素循环追加到v中
print(v) #['张三','李四','王五',1,2,3]
- reverse:反转
v = [1,3,6,4,2,5]
v.reverse()
print(v) #[5,2,4,6,3,1]
- sort:排序
v = [1,3,6,4,2,5]
v.sort(reverse = False) #从小到大排序[默认:.sort()]
print(v) #[1,2,3,4,5,6]
v.sort(reverse = True) #从大到小排序
print(v) #[6,5,4,3,2,1]
3.5 元组(tuple)
元组是不可变类型
没有自己的方法
3.6 字典(dict)
用于帮助用户去表示一个事物的信息(事物是有多高属性的)
字典是可变类型
有序字典:
from collections import OrderedDict
info = OrderedDict()
info['k1'] = 123
info['k2'] = 456
print(info.keys())
print(info.values())
print(info.items())
字典自己的方法:
- keys:获取字典中所有的键
info = {'name':'张三','age':22,'gender':'男'}
for i in info.keys():
print(i)
"""
'name'
'age'
'gender'
"""
- values:获取字典中所有的值
info = {'name':'张三','age':22,'gender':'男'}
for i in info.values():
print(i)
"""
'张三'
22
'男'
"""
- items:获取字典中所有的键值对
info = {'name':'张三','age':22,'gender':'男'}
for a,b in info.items():
print(a,b)
"""
'name','张三'
'age',22
'gender','男'
"""
- 字典的keys / values / items方法(python2与python3的区别八)
- python2:返回列表,通过索引可以取值
- python3:返回迭代器,只能通过循环取值,不能通过索引取值
- get:索引取值
info = {'name':'张三','age':22,'gender':'男'}
v1 = info.get('name')
print(v1) #'张三',相当于v1 = info['name']
v2 = info.get('hobby')
print(v2) #None
v3 = info.get('hobby',666) #如果'hobby'这个键不存在就输出666
print(v3) #666
- pop:删除(索引位置的元素)
info = {'name':'张三','age':22,'gender':'男'}
v = info.pop('name') #删除'name':'张三'这个键值对,并把'张三'赋值给v1
print(v) #'张三'
print(info) #{'age':22,'gender':'男'}
- update:批量添加(修改)
- 不存在则添加,存在则修改
info = {'name':'张三'}
info.update({'age':22,'gender':'男','name':'李四'}) #添加'age'和'gender',修改了'name'对应的值
print(info) # {'name':'李四','age':22,'gender':'男'}
3.7 集合(set)
特性:无序性,可变性,互异性
空集合表示方式:v = set()
集合自己的方法:
- add:添加(已有的不再添加)
v = {1,2,3}
v.add(4) #添加4
v.add(3) #3是已有的,不再添加
print(v) #{1,2,3,4}
- discard:删除
v = {1,2,3}
v.discard(2) #删除2
print(v) #{1,3}
- update:批量添加
v = {1,2,3}
v.update({4,5,6}) #添加4,5,6
print(v) #{1,2,3,4,5,6}
- intersection:交集
v = {1,2,3}
date = v.intersection({1,3,4}) #取v和{1,3,4}的交集
print(date) #{1,3}
- union:并集
v = {1,2,3}
date = v.union({1,3,4}) #取v和{1,3,4}的并集
print(date) #{1,2,3,4}
- difference:差集
v1 = {1,2,3}
v2 = {1,3,4}
date1 = v1.difference(v2) #取v1和v2的差集,v1中有v2中没有的
print(date1) #{2}
date2 = v2.difference(v1) #取v2和v1的差集,v2中有v1中没有的
print(date2) #{4}
- symmetric_difference:对称差集
v = {1,2,3}
date = v.symmetric_difference({1,3,4}) #取v和{1,3,4}的对称差集
print(date) #{2,4}
3.8 None
- None就是python中的空
- None转化为布尔为False
- None无任何功能,专门用于提供空值
3.9 字节(bytes)
v1 = '李杰'
"""
名称:字符串类型
用途:用于内存中做数据操作
内部:unicode
类型:<class 'str'>
"""
v2 = v1.encode('utf-8')
"""
名称:字节类型
用途:用于数据存储和网络传输
内部:其他编码(utf-8/gbk等)
类型:<class 'bytes'>
"""
# 注意:json序列化后是字符串类型,pickle序列化后是字节类型
3.10 公共功能
长度:len
索引
切片
-
步长
#笔试题:请将字符串反转 name = 'alex' val = name[::-1] print(val) #xela
for循环
-
删除:del
- remove,pop和del的区别
- remove #根据值删除,不存在则报错
- deleted = li.pop(2) #删除列表中指定的一个,另将被删除的数据赋值给deleted
- del li[2] #仅仅是删除
- del li[2:4] #del还可以删除列表中指定的一段
- remove,pop和del的区别
修改
3.11 总结
- 列表(list)/字典(dict)/集合(set)
- 不能放在集合中
- 不能作为字典的键(key)
- hash(哈希)是怎么回事?
- 因为在内部会将值进行哈希算法,并得到一个数值(对应内存地址),以后用于快速查找
- 注意:
#第1点:
info = {0,1,2,False,'你好',None,(1,2,3)}
print(info) #{0,1,2,'你好',None,(1,2,3)}
#因为False相当于0,所以False不输出
#第2点:
info = {
1:'alex', #因为True相当于1,所以把1对应的值修改了
True:'oldboy'
}
print(info) #{1:'oldboy'}
3.12 嵌套
3.12.1 列表嵌套
#示例:
users = ['alex',0,True,[11,22,33,'老男孩']]
users[3] #[11,22,33,'老男孩']
users[3][-1] #'老男孩'
users[3][-1][2] #'男'
3.12.2 列表和元组嵌套
#例1
v2 = [11,22,33,(11,22,33)]
v2[-1][1] = 99 #错误
v2[-1] = 99 #正确
#例2
v3 = (11,[1,2,3],22,33)
v3[1] = 99 #错误
v3[1][2] = 99 #正确
#总结:列表中元素可以被修改和删除,元组中元素不可被修改和删除
3.13 数据类型的相互转换
- 整型(int)
- int('字符串')/int(布尔值)
- 布尔类型(bool)
- bool(整型)/bool('字符串')/bool(列表)/bool(元组)
- 注:只有0,"",[],()转换成布尔是False,其余的都是True
- 字符串(str)
- str(整型)/str(布尔值)
- 要将列表/元组转换成字符串,可以用join
- 注意:"".join([元素必须是字符串,元素必须是字符串])
users = ['张三','李四']
val = "".join(users)
print(val) #'张三李四'
- 列表(list)
- list(元组)
- list((11,22,33)) #[11,22,33]
- 元组(tuple)
- tuple(列表)
- tuple([11,22,33]) #(11,22,33)
- 总结(常见数据类型转换):
- 字符串转数字
- 数字转字符串
- 列表转元组
- 元组转列表
- 其他转布尔
- 只有None,0,"",[],(),{},set()转换成布尔是False,其余的都是True
3.14 数据类型表示空
- None
- int:v1 = int() #0
- bool:v2 = bool() #False
- str:v3 = "" 或 v3 = str()
- list:v4 = [] 或 v4 = list()
- tuple:v5 = () 或 v5 = tuple()
- dict:v6 = {} 或 v6 = dict()
- set:v7 = set()
3.15 判断是否有敏感字符
- 字符串(str)
v = 'python全栈21期'
if '全栈' in v:
print('包含敏感字符')
- 列表(list)/元组(tuple)
v = ['alex','oldboy','张三','李四']
if '李四' in v:
print('包含敏感字符')
#元组(tuple)同理
- 字典(dict)
v = {'k1':'v1','k2':'v2','k3':'v3'}
#默认按照键判断,即判断x是否是字典中的键
if 'x' in v:
pass
#问题1:判断k1是否在v中?
v = {'k1':'v1','k2':'v2','k3':'v3'}
if 'k1' in v:
pass
#问题2:判断v2是否在v中?
#方法1:循环判断
v = {'k1':'v1','k2':'v2','k3':'v3'}
flag = '不存在'
for v in v.values():
if v == 'v2':
flag = '存在'
print(flag)
#方法2:
#强制转换成列表[v1,v2,v3]
if 'v2' in list(v.values()):
print('存在')
#问题3:判断k2:v2是否在v中?
value = v.get('k2')
if value == 'v2':
print('存在')
else:
print('不存在')
示例:判断用户输入内容是否有敏感字符
char_list = ['张三','李四','王五'] #敏感字符
content = input('请输入内容:')
flag = True
for i in char_list:
if i in content:
flag = False
break
if flag:
print(content)
else:
print('包含敏感字符')
3.16 内存相关
-
列表(list)/字典(dict)/集合(set)
-
情况一:
v1 = [1,2,3] v2 = v1 v1.append(4) #增加 print(v2) #[1,2,3,4] #在v1里面修改(增加/删除),v2也跟着改变
- 修改内存中的元素,所有指向那个内存的值都会改变
-
情况二:
v1 = [1,2,3] v2 = v1 v1 = [3,4,5] #重新赋值 print(v2) #[1,2,3] #重新赋值v1,v2不改变
- 重新赋值不修改内存中的元素,只改变值的指向
-
-
字符串(str)/元组(tuple)
- 只有情况二,只能重新赋值,不能修改
-
总结
-
在python中,为了提高性能,值若是以下情况(python小数据池),就不重新开辟内存
- 常用数字:-5~256
- 简单字符串:如'alex',除去 'alex' * 3(数字大于1) 这种情况
-
== 比较的是值是否相等,is 比较的是内存地址是否相等
#例1: v1 = [1,2] v2 = [1,2] v1 == v2 #True v1 is v2 #False #例2: v1 = [1,2] v2 = v1 v1 == v2 #True v1 is v2 #True
- 注:python小数据池除外
-
3.17 深浅拷贝
-
基本格式
v1 = [1,2,3] import copy v2 = copy.copy(v1) #浅拷贝 v3 = copy.deepcopy(v1) #深拷贝
-
整型int/布尔bool/字符串str(不可变类型)
- 深拷贝和浅拷贝的结果都是一样的
- 无法重新开辟一个内存地址,就使用同一个地址
-
列表list/字典dict/集合set(不可变类型)
- 对于其中的元素都是不可变类型时,深拷贝和浅拷贝的结果都是一样的,都是只拷贝第一层
- 对于其中元素存在可变类型时,浅拷贝只拷贝第一层,深拷贝要拷贝所有的可变类型
-
特殊类型:元组tuple
- 如果元组中不含有可变类型,同理字符串的深浅拷贝
- 如果元组中含有可变类型,同理列表的深浅拷贝
-
总结
-
浅拷贝:只拷贝第一层
深拷贝:拷贝嵌套层次中的所有可变类型
深拷贝之所以不拷贝不可变类型,是由于python小数据池的缘故
-
注意:
- 拷贝只针对可变类型:再创造一份
- 不可变类型:不会拷贝(不再创造一份出来,都是用同一个地址)
-
第四章 文件操作
4.1 文件基本操作
# 打开文件
f = open('要打开的文件路径',mode='r/w/a',encoding='文件原来写入时定义的编码')
# 操作
# f.write()
# f.read()
data = f.read() # 读取文件的内容到内存(全部)
f.write('要写入的内容')
# 关闭文件
f.close()
# 示例一 : 一般用于文字写入。
f = open('a.txt',mode='w',encoding='utf-8')
# a. 将 “你好” 根据encoding指定的编码转换成:
# “你好” --> 10001000 10001000 10001000 10001000 10001000 10001000
# b. 将二进制写入到文件中。
f.write('你好') # w打开文件,则write传入字符串
f.close()
# 示例二:一般用于图片/音频/视频/未知编码
f = open('a.txt',mode='wb')
# 1. 把要写入的字符串转换成二进制
data = "我好困"
content = data.encode('utf-8') # 将字符串按照utf-8编码转换成二进制
# 2. 再将二进制写到文件中
f.write(content) # wb打开文件,则write传入的是 二进制
f.close()
4.2 打开
打开模式:
r / w / a:只读只写字符串
r+ / w+ / a+:可读可写字符串
-
rb / wb / ab:只读只写二进制
-
字符串转换成二进制
v = 字符串 date = v.encode('utf-8')
-
二进制转换成字符串
v = 二进制 date = v.decode('utf-8')
-
r+b / w+b / a+b :可读可写二进制
4.3 操作
read() , 全部读到内存
-
read(1)
-
1表示一个字符
obj = open('a.txt',mode='r',encoding='utf-8') data = obj.read(1) # 1个字符 obj.close() print(data)
-
1表示一个字节
obj = open('a.txt',mode='rb') data = obj.read(3) # 1个字节 obj.close()
-
-
write(字符串)
obj = open('a.txt',mode='w',encoding='utf-8') obj.write('中午你') obj.close()
-
write(二进制)
obj = open('a.txt',mode='wb') # obj.write('中午你'.encode('utf-8')) v = '中午你'.encode('utf-8') obj.write(v) obj.close()
-
seek(光标字节位置),无论模式是否带b,都是按照字节进行处理。
obj = open('a.txt',mode='r',encoding='utf-8') obj.seek(3) # 跳转到指定字节位置 data = obj.read() obj.close() print(data) obj = open('a.txt',mode='rb') obj.seek(3) # 跳转到指定字节位置 data = obj.read() obj.close() print(data)
-
tell(), 获取光标当前所在的字节位置
obj = open('a.txt',mode='rb') # obj.seek(3) # 跳转到指定字节位置 obj.read() data = obj.tell() print(data) obj.close()
-
flush,强制将内存中的数据写入到硬盘
v = open('a.txt',mode='a',encoding='utf-8') while True: val = input('请输入:') v.write(val) v.flush() v.close()
4.4 关闭
- 基本方式
v = open('a.txt',mode='a',encoding='utf-8')
v.close()
- 便捷方式
with open('a.txt',mode='a',encoding='utf-8') as v:
data = v.read()
# 缩进中的代码执行完毕后,自动关闭文件
4.5 文件内容的修改
4.5.1 小文件修改
with open('a.txt',mode='r',encoding='utf-8') as f1:
data = f1.read()
new_data = data.replace('飞洒','666')
with open('a.txt',mode='w',encoding='utf-8') as f1:
data = f1.write(new_data)
4.5.2 大文件修改
f1 = open('a.txt',mode='r',encoding='utf-8')
f2 = open('b.txt',mode='w',encoding='utf-8')
for line in f1:
new_line = line.replace('阿斯','死啊')
f2.write(new_line)
f1.close()
f2.close()
with open('a.txt',mode='r',encoding='utf-8') as f1, open('c.txt',mode='w',encoding='utf-8') as f2:
for line in f1:
new_line = line.replace('阿斯', '死啊')
f2.write(new_line)
第五章 函数
5.1 函数的本质及应用场景
截至目前:面向过程编程(可读性差/可重用性差)
对于函数编程:
本质:将N行代码拿到别处并给他起一个名字,以后通过名字就可以找到这段代码并执行
- 应用场景:
- 代码重复执行
- 代码特别多超过一屏,可以选择通过函数进行代码的分割
# 面向过程编程
user_input = input('请输入角色:')
if user_input == '管理员':
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
msg = MIMEText('管理员,我想演男一号,你想怎么着都行。', 'plain', 'utf-8')
msg['From'] = formataddr(["李邵奇", '15776556369@163.com'])
msg['To'] = formataddr(["管理员", '344522251@qq.com'])
msg['Subject'] = "亲爱的管理员"
server = smtplib.SMTP("smtp.163.com", 25)
server.login("15776556369@163.com", "qq1105400511")
server.sendmail('15776556369@163.com', ['管理员', ], msg.as_string())
server.quit()
elif user_input == '业务员':
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
msg = MIMEText('业务员,我想演男一号,你想怎么着都行。', 'plain', 'utf-8')
msg['From'] = formataddr(["李邵奇", '15776556369@163.com'])
msg['To'] = formataddr(["业务员", '业务员'])
msg['Subject'] = "亲爱的业务员"
server = smtplib.SMTP("smtp.163.com", 25)
server.login("15776556369@163.com", "qq1105400511")
server.sendmail('15776556369@163.com', ['业务员', ], msg.as_string())
server.quit()
elif user_input == '老板':
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
msg = MIMEText('老板,我想演男一号,你想怎么着都行。', 'plain', 'utf-8')
msg['From'] = formataddr(["李邵奇", '15776556369@163.com'])
msg['To'] = formataddr(["老板", '老板邮箱'])
msg['Subject'] = "亲爱的老板"
server = smtplib.SMTP("smtp.163.com", 25)
server.login("15776556369@163.com", "qq1105400511")
server.sendmail('15776556369@163.com', ['老板邮箱', ], msg.as_string())
server.quit()
#函数式编程
#先不考虑是否能执行,单纯为了比较函数式编程与面向过程编程的区别
def send_email():
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
msg = MIMEText('老板,我想演男一号,你想怎么着都行。', 'plain', 'utf-8')
msg['From'] = formataddr(["李邵奇", '15776556369@163.com'])
msg['To'] = formataddr(["老板", '老板邮箱'])
msg['Subject'] = "情爱的老板"
server = smtplib.SMTP("smtp.163.com", 25)
server.login("15776556369@163.com", "qq1105400511")
server.sendmail('15776556369@163.com', ['老板邮箱', ], msg.as_string())
server.quit()
user_input = input('请输入角色:')
if user_input == '管理员':
send_email()
elif user_input == '业务员':
send_email()
elif user_input == '老板':
send_email()
5.2 函数定义
5.2.1 基本定义函数
-
基本形式
def 函数名(): #函数的定义 代码 #函数内容 函数名() #函数的执行
-
注意
- 函数如果不被调用,则内部代码永远不会被执行
- len(计算长度)是python内部写好的一个函数
5.2.2 参数(个数不限制)
5.2.2.1 基本参数知识
def get_list_date(aaa): #aaa:形式参数(形参) 任意个数
v = [11,22,33,44]
print(v[aaa])
get_list_date(1) #1:实际参数(实参) 任意类型
-
发送邮件问题
# 假如:管理员/业务员/老板用的是同一个邮箱。 def send_email(to): import smtplib from email.mime.text import MIMEText from email.utils import formataddr msg = MIMEText('导演,我想演男一号,你想怎么着都行。', 'plain', 'utf-8') msg['From'] = formataddr(["李邵奇", '15776556369@163.com']) msg['To'] = formataddr(["导演", to]) msg['Subject'] = "情爱的导演" server = smtplib.SMTP("smtp.163.com", 25) server.login("15776556369@163.com", "qq1105400511") server.sendmail('15776556369@163.com', [to, ], msg.as_string()) server.quit() def send_email(to): template = "要给%s发送邮件" %(to,) print(template) user_input = input('请输入角色:') if user_input == '管理员': send_email('xxxx@qq.com') elif user_input == '业务员': send_email('xxxxo@qq.com') elif user_input == '老板': send_email('xoxox@qq.com')
5.2.2.2 位置传参
- 传参:调用函数并传入参数
- 要求:严格按照位置进行传参
- 位置参数:positional argument
- 基本形式
def func(a,b):
print(a,b)
func(11,22) #位置都是一一对应的,a = 11,b = 22
5.2.2.3 关键字传参
关键字参数:keyword argument
-
基本形式
def func(a,b): print(a,b) func(b = 11,a = 22) #按照关键字进行传参,可以交换位置
注意:open(打开文件)是python内部写好的一个函数,运用的就是关键字传参
- 关键字传参和位置传参可以混合使用
- 位置参数必须在关键字参数的前面
- 位置参数的个数 + 关键字参数的个数 = 总参数个数
- 一个参数不能传多次
5.2.2.4 默认参数:可传可不传
-
基本形式
def func(a,b = 9): #b就是默认参数,默认值为9 #func函数接受两个参数,调用函数进行传值时,默认参数可传可不传,不传则使用默认值,传则使用传的值 print(a,b) func(123) #a = 123,b使用默认值,即b = 9 func(11,22) #a = 11,b = 22
-
对于默认值,如果是可变类型(对于函数的默认值慎用可变类型)
# 如果要想给value设置默认是空列表 # 不推荐(坑) def func(data,value=[]): pass # 推荐 def func(data,value=None): if not value: value = []
-
面试题
def func(a,b=[]): b.append(a) return b l1 = func(1) l2 = func(2,[11,22]) l3 = func(3) # [1,3] [11,22,2] [1,3] print(l1,l2,l3)
5.2.2.5 万能参数(*args / **kwargs)
-
*args
- 可以接受任意个数的位置参数,并将参数转化为元组(注意实参里有*和没有的区别)
- 只能使用位置传参
- 基本形式
def func(*args): print(args) func(1,2) #args = (1,2) func((11,22,33)) #args = ((11,22,33),) func(*(11,22,33)) #args = (11,22,33) 循环元组里的元素,加入到元组中 func(*[11,22,33,44]) #args = (11,22,33,44) 循环列表里的元素,加入到元组中 #注意实参里有*和没有的区别 #特殊情况: def func(a,*args,b): #a只能使用位置参数,b只能使用关键字参数 print(a,args,b) func(1,2,3,4,b = 5) #a = 1,args = (2,3,4),b = 5
-
**kwargs
- 可以接受任意个数的关键字参数,并将参数转化为字典(注意实参里有**和没有的区别)
- 只能使用关键字传参
- 基本形式
def func(**kwargs): print(kwargs) func(k1 = 1,k2 = 'alex') #kwargs = {'k1':1,'k2':'alex'} func(**{'k1':'v1','k2':'v2'}) #kwargs = {'k1':'v1','k2':'v2'} #注意实参里有**和没有的区别
综合运用(*args和**kwargs一起使用)
def func(*args,**kwargs):
print(args,kwargs)
func(1,2,3,4,k1 = 1,k2 = 2) #args = (1,2,3,4),kwargs = {'k1':1,'k2':2}
func(*[1,2,3],**{'k1':'v1','k2':'v2'}) #args = (1,2,3),kwargs = {'k1':'v1','k2':'v2'}
-
参数相关重点
-
定义函数
#情况一: def func(a,b): pass #情况二: def func(a,b = None): pass #情况三: def func(*args,**kwargs): pass
调用函数:位置参数 > 关键字参数
-
练习题
# 1. 请写一个函数,函数计算列表 info = [11,22,33,44,55] 中所有元素的和。
def get_sum():
info = [11,22,33,44,55]
data = 0
for item in info:
data += item
print(data)
get_sum()
# 2. 请写一个函数,函数计算列表中所有元素的和。
def get_list_sum(a1):
data = 0
for item in a1:
data += item
print(data)
get_list_sum([11,22,33])
get_list_sum([99,77,66])
v1 = [8712,123,123]
get_list_sum(v1)
# 3. 请写一个函数,函数将两个列表拼接起来。
def join_list(a1,a2):
result = []
result.extend(a1)
result.extend(a2)
print(result)
join_list([11,22,33],[55,66,77]
# 4. 计算一个列表的长度
def my_len(arg):
count = 0
for item in arg:
count += 1
print(count)
v = [11,22,33]
my_len(v)
len(v)
# 5. 发邮件的示例
def send_email(role,to):
template = "要给%s%s发送邮件" %(role,to,)
print(template)
user_input = input('请输入角色:')
if user_input == '管理员':
send_email('管理员','xxxx@qq.com')
elif user_input == '业务员':
send_email('业务员','xxxxo@qq.com')
elif user_input == '老板':
send_email('老板','xoxox@qq.com')
5.2.3 返回值(return)
- 作用
- 返回值
- 终止函数的执行
- 基本形式
def func(arg):
代码 #函数内容
return 9 #返回值为9,默认:return None
val = func('ads') #设置一个变量接收返回值
#特殊情况:
def func():
return 2,3,'alex' #返回是一个元组
val = func()
print(val) #(2,3,'alex')
- 返回值相关重点
- 函数没有返回值,默认返回:None
- 函数内部执行过程中一旦遇到return就终止
- return可以返回任意类型
# 练习题:
# 1. 写函数,计算一个列表中有多少个数字,打印: 列表中有%s个数字。
# 提示:type('x') == int 判断是否是数字。
# 方式一:
def get_list_counter1(data_list):
count = 0
for item in data_list:
if type(item) == int:
count += 1
msg = "列表中有%s个数字" %(count,)
print(msg)
get_list_counter1([1,22,3,'alex',8])
# 方式二:
def get_list_counter2(data_list):
count = 0
for item in data_list:
if type(item) == int:
count += 1
return count
v = get_list_counter1([1,22,3,'alex',8])
msg = "列表中有%s个数字" %(v,)
print(msg)
# 2. 写函数,计算一个列表中偶数索引位置的数据构造成另外一个列表,并返回。
# 方式一:
def get_data_list1(arg):
v = arg[::2]
return v
data = get_data_list1([11,22,33,44,55,66])
# 方式二:
def get_data_list2(arg):
v = []
for i in range(0,len(arg)):
if i % 2 == 0:
v.append(arg[i])
return v
data = get_data_list2([11,22,33,44,55,66])
# 3. 读取文件,将文件的内容构造成指定格式的数据,并返回。
"""
a.log文件
alex|123|18
eric|uiuf|19
...
目标结构:
a. ["alex|123|18","eric|uiuf|19"] 并返回。
b. [['alex','123','18'],['eric','uiuf','19']]
c. [
{'name':'alex','pwd':'123','age':'18'},
{'name':'eric','pwd':'uiuf','age':'19'},
]
"""
def a():
info = []
with open('a.log',mode='r',encoding='utf-8') as f:
for line in f:
line = line.strip()
info.append(line)
return info
def b():
info = []
with open('a.log',mode='r',encoding='utf-8') as f:
for line in f:
line = line.strip()
v = line.split('|')
info.append(v)
return info
def c():
info = []
with open('a.log',mode='r',encoding='utf-8') as f:
for line in f:
line = line.strip()
list = line.split('|')
v = {}
v['name'] = list[0]
v['pwd'] = list[1]
v['age'] = list[2]
info.append(v)
return info
date1 = a()
date2 = b()
date3 = c()
print(date1,date2,date3)
-
数据类型中的方法有没有返回值
-
无返回值
#示例: v = [11,22,33] v.append(99)
-
仅有返回值:
#示例一: v = "alex" result = v.split('l') #示例二: v = {'k1':'v2'} result1 = v.get('k1') result2 = v.keys()
-
有返回+修改数据
#示例: v = [11,22,33] result = v.pop() # 将被删除的数据赋值给result
-
常用需记住的
- str
- strip,返回字符串
- split,返回列表
- replace,返回字符串
- join,返回字符串
- list
- append,无
- insert,无
- pop,返回要删除的数据
- remove,无
- find/index,返回索引的位置的数据
- dict
- get,返回索引键的值
- keys,返回字典的所有键
- values,返回字典的所有值
- items,返回字典所有的键值对
- str
-
5.2.4 总结
- 函数的基本结构:
#情况一
def f1():
函数内容
f1()
#情况二
def f2(a):
函数内容
f2(1)
#情况三
def f3():
函数内容
return
v1 = f3()
#情况四
def f4(a1,a2):
函数内容
return a1+a2
v2 = f4(1,7)
- 函数内部的数据是否会混乱?
- 函数内部执行相互之间不会混乱
- 执行完毕 + 内部元素不被其他人使用 => 销毁
5.3 函数小高级
5.3.1 函数名可以当作变量来使用
#示例一:
def func():
print(123)
func_list = [func, func, func]
# func_list[0]()
# func_list[1]()
# func_list[2]()
for item in func_list:
v = item()
print(v)
#示例二:
def func():
print(123)
def bar():
print(666)
info = {'k1': func, 'k2': bar}
info['k1']()
info['k2']()
#注意区别:
def func():
return 123
func_list1 = [func,func,func]
func_list2 = [func(),func(),func()]
print(func_list1)
print(func_list2)
5.3.2 函数可以当作参数进行传递
#示例:
def func(arg):
v1 = arg()
print(v1)
def show():
print(666)
result = func(show)
print(result)
#面试题:多个函数的调用
def func():
print('话费查询')
def bar():
print('语音沟通')
def base():
print('业务办理')
def show():
print('流量查询')
def test():
print('人工服务')
info = {
'f1': func,
'f2': bar,
'f3':base,
'f4':show,
'f5':test
}
choice = input('请选择要选择功能:')
function_name = info.get(choice)
if function_name:
function_name()
else:
print('输入错误')
5.3.3 匿名函数: lambda表达式
作用:用于表达简单的函数
-
基本形式:
#三元运算,为了解决简单的if else的情况 if 1 == 1: a = 123 else: a = 456 #用三元运算表示: a = 123 if 1 == 1 else 456 #lambda表达式,为了解决简单函数的情况 def func(a1,a2): return a1 + a2 #用lambda表达式表示: func = lambda a1,a2: a1+a2 #隐含了return
-
重点:
- lambda表达式只能用一行表示函数
- 用lambda表达式表示函数时,无法设置新变量,只能用参数作变量
- 列表所有方法基本上都是返回None,字符串的所有方法基本上都是返回新值
-
练习题
# 练习题1 USER_LIST = [] def func0(x): v = USER_LIST.append(x) return v result = func0('alex') print(result) #None # 练习题2 def func0(x): v = x.strip() return v result = func0(' alex ') print(result) #'alex' # 练习题3 USER_LIST = [] func1 = lambda x: USER_LIST.append(x) v1 = func1('alex') print(v1) #None print(USER_LIST) #['alex'] # 练习题4 func1 = lambda x: x.split('l') v1 = func1('alex') print(v1) #['a','ex'] # 练习题5 func_list = [lambda x:x.strip(), lambda y:y+199,lambda x,y:x+y] v1 = func_list[0]('alex ') print(v1) #'alex' v2 = func_list[1](100) print(v2) #299 v3 = func_list[2](1,2) print(v3) #3
5.4 函数中高级
5.4.1 函数可以做返回值
#示例:
def func():
print(123)
def bar():
return func
v = bar()
v()
5.4.2 闭包
- 概念:为函数创建一块区域并为其维护自己数据,以后执行方便调用
- 应用场景:
- 装饰器
- SQLAlchemy源码
#示例:
name = 'oldboy'
def bar(name):
def inner():
print(name)
return inner
v1 = bar('alex') # { name=alex, inner } # 闭包,为函数创建一块区域(内部变量供自己使用),为他以后执行提供数据。
v2 = bar('eric') # { name=eric, inner }
v1()
v2()
#区分:
# 不是闭包
def func1(name):
def inner():
return 123
return inner
# 是闭包:封装值 + 内层函数需要使用。
def func2(name):
def inner():
print(name)
return 123
return inner
#练习题:
#第一题
name = 'alex'
def base():
print(name)
def func():
name = 'eric'
base()
func()
# 第二题
name = 'alex'
def func():
name = 'eric'
def base():
print(name)
base()
func()
# 第三题
name = 'alex'
def func():
name = 'eric'
def base():
print(name)
return base
base = func()
base()
#注意:函数在何时被谁创建?
#示例:
info = []
def func():
print(item)
for item in range(10):
info.append(func)
info[0]()
#面试题
info = []
def func(i):
def inner():
print(i)
return inner
for item in range(10):
info.append(func(item))
info[0]()
info[1]()
info[4]()
5.4.3 高阶函数
- 把函数当作参数传递
- 把函数当作返回值
- 注意:对函数进行赋值
5.5 内置函数
函数分为自定义函数和内置函数
python内置函数分类:
5.5.1 强制转换
- int() / str() / bool() / list() / tuple() / dict() / set()
5.5.2 输入输出
- input() / print()
5.5.3 数学相关
abs():计算绝对值
sum():求和
-
float():转化为浮点型(小数)
v = 55 v1 = float(55) print(v1) #55.0
- 补充:int(55.5) #只保留整数:55
max():找到最大值
min():找到最小值
-
divmod():取两数相除的商和余数
#示例: a,b = divmod(1001,5) print(a,b) #a=200,b=1
-
注意:divmod在分页展示时用得比较多
# 练习题 请通过分页对数据进行展示 """ 要求: 每页显示10条数据 让用户输入要查看的页面:页码 """ USER_LIST = [] for i in range(1,836): temp = {'name':'你-%s' %i,'email':'123%s@qq.com' %i } USER_LIST.append(temp) # 数据总条数 total_count = len(USER_LIST) # 每页显示10条 per_page_count= 10 # 总页码数 max_page_num,a = divmod(total_count,per_page_count) if a>0: max_page_num += 1 while True: pager = int(input('要查看第几页:')) if pager < 1 or pager > max_page_num: print('页码不合法,必须是 1 ~ %s' %max_page_num ) else: start = (pager-1) * per_page_count end = pager * per_page_count data = USER_LIST[start:end] for item in data: print(item)
-
-
pow():指数
v = pow(2,3) #相当于2**3 print(v) # 8
round():保留几位小数,默认保留整数,还会四舍五入
v = round(1.127,2) #第二个数代表保留几位小数,默认是None
print(v) # 1.13 四舍五入
5.5.4 进制转换相关
bin():将十进制转换成二进制
oct():将十进制转换成八进制
-
int():将其他进制转换成十进制
- 默认:base = 10
# 二进制转化成十进制 v1 = '0b1101' result = int(v1,base=2) #base=2说明读取的是二进制 print(result) # 八进制转化成十进制 v1 = '0o1101' result = int(v1,base=8) print(result) # 十六进制转化成十进制 v1 = '0x1101' result = int(v1,base=16) print(result)
hex():将十进制转换成十六进制
#1字节等于8位
# IP: 192.168.12.79 -> 001010010 . 001010010 . 001010010 . 001010010
# 请将 ip = "192.168.12.79" 中的每个十进制数转换成二进制并通过,连接起来生成一个新的字符串。
ip = "192.168.12.79"
ip_list = ip.split('.') # ['192','168','12','79']
result = []
for item in ip_list:
result.append(bin(int(item)))
print(','.join(result))
#面试题:
# 请将 ip = "192.168.12.79" 中的每个十进制数转换成二进制:
# 0010100100001010010001010010001010010 -> 十进制的值。
# 3232238671
ip = '192.168.12.79'
v = ip.split('.')
info = []
for i in v:
date = str(bin(int(i)))
if len(date) > 10:
date = date[-8:]
else:
count = 10 - len(date)
date = date.replace('0b','0'*count)
info.append(date)
val = "".join(info)
a = int(val,base=2)
print(a)
5.5.5 编码相关
chr():将十进制数字转换成 unicode 编码中的对应字符串
-
ord():根据字符在 unicode 编码中找到其对应的十进制
#应用:生成随机验证码 import random # 导入一个模块 def get_random_code(length=6): data = [] for i in range(length): v = random.randint(65,90) data.append(chr(v)) return ''.join(data) code = get_random_code() print(code)
5.5.6 内置函数高级
-
map(函数,可迭代对象):一起执行
- 循环每个元素(第二个参数),然后让每个元素执行函数(第一个参数),将每个函数执行的结果保存到新的列表中,并返回
#示例: v1 = [11,22,33,44] result = map(lambda x:x+100,v1) print(list(result))
-
filter(函数,可迭代对象):进行筛选
#示例: v1 = [11,22,33,'asd',44,'xf'] def func(x): if type(x) == int: return True return False result = filter(func,v1) print(list(result)) # 用lambda表达式: result = filter(lambda x: True if type(x) == int else False ,v1) print(list(result)) # 相当于: result = filter(lambda x: type(x) == int ,v1) print(list(result))
-
map / filter(python2与python3的区别九)
- python2:返回列表,直接创建值,可以通过索引取值
- python3:返回迭代器,不直接创建值,通过循环,边循环边创建
-
reduce(函数,可迭代对象):得到结果
import functools v1 = ['wo','hao','e'] def func(x,y): return x+y result = functools.reduce(func,v1) print(result) # 用lambda表达式: result = functools.reduce(lambda x,y:x+y,v1) print(result)
5.5.7 类相关
-
type():查看数据类型
class Foo: pass obj = Foo() if type(obj) == Foo: print('obj是Foo类的对象')
-
issubclass(类,类或其基类):判断前一个类是否是后一个类或其基类的子类
- 结果是布尔类型,是 -> True,否 -> False
class Base: pass class Base1(Base): pass class Foo(Base1): pass class Bar: pass print(issubclass(Bar,Base)) print(issubclass(Foo,Base))
-
isinstance(对象,类或其基类):判断一个对象是否是一个类或其基类的实例(对象)
- 结果是布尔类型,是 -> True,否 -> False
- 注意:判断一个对象是否是一个类的实例(对象),一定要用type,不要用isinstance
class Base(object): pass class Foo(Base): pass obj = Foo() print(isinstance(obj,Foo)) # 判断obj是否是Foo类或其基类的实例(对象) print(isinstance(obj,Base)) # 判断obj是否是Foo类或其基类的实例(对象)
-
super().方法名():根据self对象所属的类的继承关系,按照顺序依次找方法并执行(找到第一个为止)
class Base(object): def func(self): super().func() # 根据self对象所属类的继承关系,按照顺序挨个找func方法并执行(找到第一个为止) print('base.func') class Bar(object): def func(self): print('bar.func') class Foo(Base,Bar): # Foo -> Base -> Bar pass obj = Foo() obj.func()
5.5.8 其他
- len() :计算长度
- open() :打开文件
- range()
- id() :查看内存地址
5.7 作用域
5.7.1 分类
-
全局作用域:在python中,相当于一个py文件
- 全局作用域中的变量称为全局变量
- 全局变量必须全用大写
-
局部作用域:在python中,相当于一个函数
- 局部作用域中的变量称为局部变量
- 局部变量则用小写
USER_LIST = [11,22,3] #全局变量 def func(): name = 'asdf' #局部变量 USER_LIST.append(12) USER_LIST.append(name) func() print(USER_LIST)
5.7.2 递归
-
函数自己调用自己。(效率低)
def func(): print(1) func() func()
# 递归的返回值 def func(a): if a == 5: return 100000 result = func(a+1) + 10 v = func(1) name = 'alex' def func(): def inner(): print(name) return inner v =func()
5.7.3 总结
在python中,一个函数就是一个作用域
-
作用域中查找数据规则:
- 优先在自己的作用域里找数据
- 自己没有就去 '父级' 中找,没有就去 '父级' 的 '父级' 中找,直到找至全局作用域
- 如果最后全局作用域中也没有,就会报错
- 寻找时注意:父级作用域中的值到底是什么
#示例一: x = 10 def func(): x = 9 print(x) def x1(): x = 8 print(x) func() # 9 #示例二: x = 10 def func(): x = 9 print(x) def x1(): x = 8 print(x) x1() func() # 9 8 #示例三: x = 10 def func(): x = 9 print(x) def x1(): x = 8 print(x) print(x) x1() func() # 9 9 8 #示例四: x = 10 def func(): x = 9 print(x) def x1(): x = 8 print(x) x1() print(x) func() # 9 8 9 #示例五: x = 10 def func(): x = 9 print(x) def x1(): print(x) x1() print(x) func() # 9 9 9 #示例六: x = 10 def func(): x = 8 print(x) def x1(): print(x) x = 9 x1() x = 10 print(x) func() # 8 9 10 #示例七: x = 10 def func(): x = 8 print(x) def x1(): print(x) x1() x = 9 x1() x = 10 print(x) func() # 8 8 9 10
-
对于子作用域:
只能找到 '父级' 中的值,默认无法重新为 '父级' 的变量进行赋值
-
如果非要对变量进行重新赋值,使用 global / nonlocal 进行强制赋值
- global:直接找到全局的变量,再进行重新赋值,其他的不更改
- nonlocal:只找到 '父级' 的变量,进行重新赋值,其他的不更改
- 建议:一般不要使用,以免造成代码混乱
#global示例: name = 'oldboy' def func(): name = 'alex' def inner(): global name #直接找到全局的name name = 'abc' #再进行重新赋值 inner() print(name) #'alex' func() print(name) #'abc' #nonlocal示例: name = "oldboy" def func(): name = 'alex' def inner(): nonlocal name #找到上一级的name name = 'abc' #再进行重新赋值 inner() print(name) #'abc' func() print(name) #"oldboy"
5.8 推导式
5.8.1 列表推导式
# 目的:方便的生成一个列表
# 格式:
v1 = [i for i in 可迭代对象 ]
v2 = [i for i in 可迭代对象 if 条件 ] #条件为true才进行append
# 示例:
v1 = [ i for i in 'alex' ]
v2 = [i+100 for i in range(10)]
v3 = [99 if i>5 else 66 for i in range(10)]
def func():
return 100
v4 = [func for i in range(10)]
v5 = [lambda : 100 for i in range(10)]
result = v5[9]()
v6 = [lambda :i for i in range(10)]
result = v6[5]()
# 新浪微博面试题
v7 = [lambda x:x*i for i in range(10)]
# 1.请问 v7 是什么?
# 2.请问 v7[0](2) 的结果是什么?
# 面试题
def num():
return [lambda x:i*x for i in range(4)]
# num() -> [函数,函数,函数,函数]
print([ m(2) for m in num() ]) # [6,6,6,6]
5.8.2 集合推导式
# 目的:方便的生成一个集合
# 格式:
v1 = { i for i in 'alex' }
5.8.3 字典推导式
# 目的:方便的生成一个字典
# 格式:
v1 = { 'k'+str(i):i for i in range(10)}
5.8.4 生成器推导式
# 列表推导式,立即循环创建所有元素
"""
def func():
result = []
for i in range(10):
result.append(i)
return result
v1 = func()
"""
v1 = [i for i in range(10)]
print(v1)
# 生成器推导式,创建了一个生成器,内部循环为执行
"""
def func():
for i in range(10):
yield i
v2 = func()
"""
v2 = (i for i in range(10))
for item in v2:
print(item)
# 面试题:请比较 [i for i in range(10)] 和 (i for i in range(10)) 的区别?
5.9 装饰器
5.8.1 目的
- 在不改变原函数内部代码的基础上,在函数执行之前和之后自动执行某个功能
5.8.2 应用场景
- 想要为函数扩展功能时,可以选择用装饰器
5.8.3 基本装饰器
-
基本格式:
def func(arg): def inner(): v = arg() return v return inner # 重点: # 第一步:执行func函数并将下面的函数参数传递,相当于:func(index) # 第二步:将func的返回值重新赋值给下面的函数名。 index = func(index) @func def index(): print(123) return 666 print(index)
-
总结
- 编写格式:
def 外层函数(参数): def 内层函数(*args,**kwargs) return 参数(*args,**kwargs) return 内层函数
- 应用格式:
@外层函数 def index(): #要装饰的函数 pass index()
# 装饰器的编写 def x(func): def y(): # 前 ret = func() # 后 return ret return y # 装饰器的应用 @x def index(): return 10 # 执行函数,自动触发装饰器了 v = index() print(v)
-
示例:
def func(arg): def inner(): print('before') v = arg() print('after') return v return inner def index(): print('123') return '666' # 示例一 v1 = index() # 执行index函数,打印123并返回666赋值给v1. # 示例二 v2 = func(index) # v2是inner函数,arg=index函数 index = 666 v3 = v2() # 示例三 v4 = func(index) index = v4 # index ==> inner index() # 示例四 index = func(index) index()
5.8.4 带参数的装饰器
-
应用场景:flask框架 / django缓存 / 写装饰器实现被装饰的函数要执行N次
# 第一步:执行 ret = xxx(index) # 第二步:将返回值赋值给 index = ret @xxx def index(): pass # 第一步:执行 v1 = uuu(9) # 第二步:ret = v1(index) # 第三步:index = ret @uuu(9) def index(): pass
-
区别:
# 普通装饰器 def wrapper(func): def inner(*args,**kwargs): data = func(*args,**kwargs) # 执行原函数并获取返回值 return data return inner @wrapper def index(): pass # 带参数装饰器 def x(counter): def wrapper(func): def inner(*args,**kwargs): data = func(*args,**kwargs) # 执行原函数并获取返回值 return data return inner return wrapper @x(9) def index(): pass
-
练习题
# 习题一: # 写一个带参数的装饰器,实现:参数是多少,被装饰的函数就要执行多少次,把每次结果添加到列表中,最终返回列表。 def xxx(counter): def wrapper(func): def inner(*args,**kwargs): v = [] for i in range(counter): data = func(*args,**kwargs) # 执行原函数并获取返回值 v.append(data) return v return inner return wrapper @xxx(5) def index(): return 8 v = index() print(v) # 习题二: # 写一个带参数的装饰器,实现:参数是多少,被装饰的函数就要执行多少次,并返回最后一次执行的结果【面试题】 def xxx(counter): def wrapper(func): def inner(*args,**kwargs): for i in range(counter): data = func(*args,**kwargs) # 执行原函数并获取返回值 return data return inner return wrapper @xxx(5) def index(): return 8 v = index() print(v) # 习题三: # 写一个带参数的装饰器,实现:参数是多少,被装饰的函数就要执行多少次,并返回执行结果中最大的值。 def xxx(counter): def wrapper(func): def inner(*args,**kwargs): value = 0 for i in range(counter): data = func(*args,**kwargs) # 执行原函数并获取返回值 if data > value: value = data return value return inner return wrapper @xxx(5) def index(): return 8 v = index() print(v)
5.10 迭代器
5.10.1 基本知识
用途:对 某种对象(str/list/tuple/dict/set类创建的对象-可迭代对象)中的元素进行逐一获取
表象:具有
__next__
方法且每次调用都获取可迭代对象中的元素(从前到后一个一个获取)-
示例:
- 列表转换成迭代器:
- v1 = iter([11,22,33,44])
v1 = [11,22,33,44].__iter__()
- 迭代器想要获取每个值:反复调用
val = v1.__next__()
v1 = [11,22,33,44] # 列表转换成迭代器 v2 = iter(v1) # 迭代器获取每个值 result1 = v2.__next__() print(result1) result2 = v2.__next__() print(result2) result3 = v2.__next__() print(result3) result4 = v2.__next__() print(result4) result5 = v2.__next__() print(result5) # 报错:Stoplteration 表示已经迭代结束
- 列表转换成迭代器:
-
for循环:运用了迭代器
v1 = [11,22,33,44] # 1.内部会将v1转换成迭代器 # 2.内部反复执行 迭代器.__next__() # 3.取完不报错 for item in v1: print(item)
5.10.2 可迭代对象
表象:可以被for循环的对象就可以称为是可迭代对象
-
如何让一个对象变成可迭代对象?
- 在类中实现
__iter__
方法且返回一个迭代器(生成器)
# 示例一: class Foo: def __iter__(self): return iter([1,2,3,4]) obj = Foo() # 示例二: class Foo: def __iter__(self): yield 1 yield 2 yield 3 obj = Foo()
- 在类中实现
注意:只要能被for循环,就是去看他内部的
__iter__
方法
5.11 生成器
5.11.1 基本知识
可以理解为:函数的变异、特殊的迭代器、特殊的可迭代对象
-
生成器的作用:
- 生成数据
- 迭代
-
示例:
# 生成器函数(内部是否包含yield) def func(): print('F1') yield 1 print('F2') yield 2 print('F3') yield 100 print('F4') # 函数内部代码不会执行,返回一个 生成器对象 。 v1 = func() # 生成器是可以被for循环,一旦开始循环那么函数内部代码就会开始执行。 for item in v1: print(item)
5.11.2 关键字
-
yield
- 用途:判断函数是否是生成器函数
-
yield from
- 用途:从当前生成器函数跳到其他生成器函数中,执行结束后再回原函数继续执行下面代码
def base(): yield 88 yield 99 def func(): yield 1 yield 2 yield from base() # 跳到base函数 yield 3 result = func() for item in result: print(item) # 1 2 88 99 3
5.11.3 总结
-
重点:
- 函数中如果存在yield,那么该函数就是一个生成器函数
- 调用生成器函数会返回一个生成器
- 生成器只有被for循环时,生成器函数内部的代码才会执行,每次循环都会获取yield返回的值
-
建议:
生成器函数中一般不要有return
-
如果需要终止生成器函数中的循环,可以用return
def func(): count = 1 while True: yield count count += 1 if count == 100: return val = func() for item in val: print(item)
-
生成器示例:读取大文件内容
def func(): # 分批去读取文件中的内容,将文件的内容返回给调用者。 cursor = 0 while True: f = open('db', 'r', encoding='utf-8') # 通过网络连接上redis # 代指 redis[0:10] f.seek(cursor) data_list =[] for i in range(10): line = f.readline() if not line: return data_list.append(line) cursor = f.tell() f.close() # 关闭与redis的连接 for row in data_list: yield row for item in func(): print(item)
第六章 模块
6.1 模块的定义
- 模块的定义
- 可以吧一个py文件或一个文件夹(包)当作一个模块,以便于以后其他py文件的调用
- 包的定义(python2与python3的区别七)
- python2:文件夹中必须有_ _ init _ _.py文件
- python3:不需要有_ _ init _ _.py文件
- 建议:推荐以后写代码,无论是python2还是python3,都要加上此文件
6.2 模块的分类(类库)
6.2.1 内置模块
- python内部提供的功能
- 导入模块后,直接使用即可
6.2.1.1 random
- 随机数模块
- random.randint(起始,终止):得到一个随机数
import random # 导入一个模块
v = random.randint(起始,终止) # 得到一个随机数
#示例:生成随机验证码
import random
def get_random_code(length=6):
data = []
for i in range(length):
v = random.randint(65,90)
data.append(chr(v))
return ''.join(data)
code = get_random_code()
print(code)
6.2.1.2 hashlib
- 加密模块
- hashlib.md5(): md5 加密函数
# 将指定的 “字符串” 进行 加密
import hashlib # 导入一个模块
def get_md5(data): # md5 加密函数
obj = hashlib.md5()
obj.update(data.encode('utf-8'))
result = obj.hexdigest()
return result
val = get_md5('123')
print(val)
# 加盐
import hashlib
def get_md5(data):
obj = hashlib.md5("sidrsdxff123ad".encode('utf-8')) # 加盐
obj.update(data.encode('utf-8'))
result = obj.hexdigest()
return result
val = get_md5('123')
print(val)
# 应用:用户注册+用户登录
import hashlib
USER_LIST = []
def get_md5(data): # md5 加密函数
obj = hashlib.md5("12:;idrsicxwersdfsaersdfs123ad".encode('utf-8')) # 加盐
obj.update(data.encode('utf-8'))
result = obj.hexdigest()
return result
def register(): # 用户注册函数
print('**************用户注册**************')
while True:
user = input('请输入用户名:')
if user == 'N':
return
pwd = input('请输入密码:')
temp = {'username':user,'password':get_md5(pwd)}
USER_LIST.append(temp)
def login(): # 用户登录函数
print('**************用户登陆**************')
user = input('请输入用户名:')
pwd = input('请输入密码:')
for item in USER_LIST:
if item['username'] == user and item['password'] == get_md5(pwd):
return True
register()
result = login()
if result:
print('登陆成功')
else:
print('登陆失败')
6.2.1.3 getpass
- 只能在终端运行
- getpass.getpass:输入密码时不显示
import getpass # 导入一个模块
pwd = getpass.getpass('请输入密码:')
if pwd == '123':
print('输入正确')
6.2.1.4 time【常用】
- 时间模块
-
time.time:时间戳(从1970年到现在经历的秒数)
# https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=4ZwIFHM6iw==&tip=1&r=-781028520&_=1555559189206
time.sleep:等待的秒数
time.timezone
-
示例
# 计算函数执行时间 import time def wrapper(func): def inner(): start_time = time.time() v = func() end_time = time.time() print(end_time-start_time) return v return inner @wrapper def func1(): time.sleep(2) print(123) func1()
6.2.1.5 datetime
- 时间模块
datetime.now():当前本地时间
-
datetime.utcnow():当前UTC时间
import time from datetime import datetime,timezone,timedelta # 获取datetime格式时间 # 当前本地时间 v1 = datetime.now() # 当前东7区时间 tz = timezone(timedelta(hours=7)) v2 = datetime.now(tz) # 当前UTC时间 v3 = datetime.utcnow() print(v3)
-
相互转换
import time from datetime import datetime,timedelta # 1.datetime格式和字符串的相互转换 # 把datetime格式转换成字符串:strftime v1 = datetime.now() val = v1.strftime("%Y-%m-%d %H:%M:%S") # 字符串转成datetime格式:strptime v1 = datetime.strptime('2011-11-11','%Y-%m-%d') # 2.datetime时间的加减 v1 = datetime.strptime('2011-11-11','%Y-%m-%d') v2 = v1 - timedelta(days=140) # 再转换成字符串 date = v2.strftime('%Y-%m-%d') # 3.时间戳和datetime的相互转换 # 时间戳转换成datetime格式:fromtimestamp ctime = time.time() v1 = datetime.fromtimestamp(ctime) # datetime格式转换成时间戳:timestamp v1 = datetime.now() val = v1.timestamp()
6.2.1.6 sys
- python解释器相关数据
sys.getrefcount:获取一个值的应用计数
sys.getrecursionlimit:python默认支持的递归数量
-
sys.stdout.write:输入输出
-
补充:\n:换行 \t:制表符 \r:回到当前行的起始位置
import time for i in range(1,101): msg = "%s%%\r" %i print(msg,end='') time.sleep(0.05)
示例:读取文件的进度条
import os # 1. 读取文件大小(字节) file_size = os.stat('20190409_192149.mp4').st_size # 2.一点一点的读取文件 read_size = 0 with open('20190409_192149.mp4',mode='rb') as f1,open('a.mp4',mode='wb') as f2: while read_size < file_size: chunk = f1.read(1024) # 每次最多去读取1024字节 f2.write(chunk) read_size += len(chunk) val = int(read_size / file_size * 100) print('%s%%\r' %val ,end='')
-
-
sys.argv:获取用户执行脚本时,传入的参数
- 示例:让用户执行脚本传入要删除的文件路径,在内部帮助用将目录删
""" 让用户执行脚本传入要删除的文件路径,在内部帮助用将目录删除。 C:\Python36\python36.exe D:/code/s21day14/7.模块传参.py D:/test C:\Python36\python36.exe D:/code/s21day14/7.模块传参.py """ import sys # 获取用户执行脚本时,传入的参数。 # C:\Python36\python36.exe D:/code/s21day14/7.模块传参.py D:/test # sys.argv = [D:/code/s21day14/7.模块传参.py, D:/test] path = sys.argv[1] # 删除目录 import shutil shutil.rmtree(path)
sys.exit(0):程序终止,0代表正常终止
-
sys.path:默认python去导入模块时,会按照sys.path中的路径
- 添加目录:sys.path.append('目录')
import sys sys.path.append('D:\\')
6.2.1.7 os【常用】
- 和操作系统相关的数据
os.path.exists(path):如果path存在,返回True;如果path不存在,返回False
os.stat('文件路径').st_size:获取文件大小
-
os.path.abspath():获取一个文件的绝对路径
import os v1 = os.path.abspath(path) print(v1)
-
os.path.dirname():获取路径的上级目录
import os v = r"D:\code\s21day14\20190409_192149.mp4" print(os.path.dirname(v))
-
补充:转义
v1 = r"D:\code\s21day14\n1.mp4" (推荐) v2 = "D:\\code\\s21day14\\n1.mp4"
-
-
os.path.join:路径的拼接
import os path = "D:\code\s21day14" # user/index/inx/fasd/ v = 'n.txt' result = os.path.join(path,v) print(result)
-
os.listdir:查看一个目录下所有的文件【第一层】
import os result = os.listdir(r'D:\code\s21day14') for path in result: print(path)
-
os.walk:查看一个目录下所有的文件【所有层】
import os result = os.walk(r'D:\code\s21day14') for a,b,c in result: # a,正在查看的目录 b,此目录下的文件夹 c,此目录下的文件 for item in c: path = os.path.join(a,item) print(path)
os.makedir:创建目录,只能生产一层目录(基本不用这个)
-
os.makedirs:创建目录及其子目录(推荐使用)
# 将内容写入指定文件中 import os file_path = r'db\xx\xo\xxxxx.txt' file_folder = os.path.dirname(file_path) if not os.path.exists(file_folder): os.makedirs(file_folder) with open(file_path,mode='w',encoding='utf-8') as f: f.write('asdf')
-
os.rename:重命名
# 将db重命名为sb import os os.rename('db','sb')
6.2.1.8 shutil
- 用途:删除、重命名、压缩、解压等
-
shutil.rmtree(path):删除目录
# 删除目录 import shutil shutil.rmtree(path)
-
shutil.move:重命名
# 重命名 import shutil shutil.move('test','ttt')
-
shutil.make_archive:压缩文件
# 压缩文件 import shutil shutil.make_archive('zzh','zip','D:\code\s21day16\lizhong')
-
shutil.unpack_archive:解压文件
# 解压文件 import shutil shutil.unpack_archive('zzh.zip',extract_dir=r'D:\code\xxxxxx\xxxx',format='zip')
-
示例
import os import shutil from datetime import datetime ctime = datetime.now().strftime('%Y-%m-%d-%H-%M-%S') # 1.压缩lizhongwei文件夹 zip # 2.放到到 code 目录(默认不存在) # 3.将文件解压到D:\x1目录中。 if not os.path.exists('code'): os.makedirs('code') shutil.make_archive(os.path.join('code',ctime),'zip','D:\code\s21day16\lizhongwei') file_path = os.path.join('code',ctime) + '.zip' shutil.unpack_archive(file_path,r'D:\x1','zip')
6.2.1.9 json
- json是一个特殊的字符串,长得像列表/字典/字符串/数字等嵌套
- 序列化:把python中的值转化为json格式的字符串
- 反序列化:将json格式的字符串转换成python的数据类型
- json格式要求:
- 只包含 int / str / list / dict
- 最外层必须是 list / dict
- 在json中,内部str必须是双引号
-
json.dumps():序列化
- json只支持 dict / list / typle / str / int / float / True / False / None 序列化
- 字典或列表中如果有中文,序列化时,如果想保留中文显示
import json v = {'k1':'alex','k2':'李杰'} val = json.dumps(v,ensure_ascii = False)
-
json.loads():反序列化
import json # 序列化,将python的值转换为json格式的字符串。 v = [12,3,4,{'k1':'v1'},True,'asdf'] v1 = json.dumps(v) print(v1) # 反序列化,将json格式的字符串转换成python的数据类型 v2 = '["alex",123]' print(type(v2)) v3 = json.loads(v2) print(v3,type(v3))
-
json.dump:打开文件,序列化后,写入文件
import json v = {'k1':'alex','k2':'李杰'} f = open('x.txt',mode='w',encoding='utf-8') val = json.dump(v,f) print(val) f.close()
-
json.load:打开文件,读取文件内容
import json v = {'k1':'alex','k2':'李杰'} f = open('x.txt',mode='r',encoding='utf-8') data = json.load(f) f.close() print(data,type(data))
6.2.1.10 pickle
- pickle与json的区别
- json
- 优点:所有语言通用
- 缺点:只能序列化基本的数据类型 list/dict 等
- pickle
- 优点:python中所有的东西都能被他序列化(socket对象)
- 缺点:序列化的内容只有python认识
- json
-
pickle.dumps:序列化
- 序列化后的东西不可读
-
pickle.loads:反序列化
# 序列化 v = {1,2,3,4} val = pickle.dumps(v) print(val) # 反序列化 data = pickle.loads(val) print(data,type(data))
pickle.dump:写入文件(注意:mode='wb')
-
pickle.load:读取文件(注意:mode='rb')
# 写入文件 v = {1,2,3,4} f = open('x.txt',mode='wb') val = pickle.dump(v,f) f.close() # 读取文件 f = open('x.txt',mode='rb') data = pickle.load(f) f.close() print(data)
6.2.1.11 copy
- 拷贝模块
copy.copy:浅拷贝
-
copy.deepcopy:深拷贝
import copy v1 = [1,2,3] v2 = copy.copy(v1) #浅拷贝 v3 = copy.deepcopy(v1) #深拷贝
6.2.1.12 importlib
-
importlib.import_module:通过字符串的形式导入模块
#示例一: import importlib # 用字符串的形式导入模块。 redis = importlib.import_module('utils.redis') # 用字符串的形式去对象(模块)找到他的成员。 getattr(redis,'func')() #示例二: import importlib middleware_classes = [ 'utils.redis.Redis', # 'utils.mysql.MySQL', 'utils.mongo.Mongo' ] for path in middleware_classes: module_path,class_name = path.rsplit('.',maxsplit=1) module_object = importlib.import_module(module_path)# from utils import redis cls = getattr(module_object,class_name) obj = cls() obj.connect()
6.2.1.13 logging
日志模块
日志处理本质:Logger/FileHandler/Formatter
-
推荐处理日志方式
import logging file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf-8',) logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', handlers=[file_handler,], level=logging.ERROR ) logging.error('你好')
-
推荐处理日志方式 + 日志分割
import time import logging from logging import handlers # file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf-8',) file_handler = handlers.TimedRotatingFileHandler(filename='x3.log', when='s', interval=5, encoding='utf-8') logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', handlers=[file_handler,], level=logging.ERROR ) for i in range(1,100000): time.sleep(1) logging.error(str(i))
注意事项:
# 在应用日志时,如果想要保留异常的堆栈信息。 import logging import requests logging.basicConfig( filename='wf.log', format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', level=logging.ERROR ) try: requests.get('http://www.xxx.com') except Exception as e: msg = str(e) # 调用e.__str__方法 logging.error(msg,exc_info=True)
6.2.2 第三方模块
6.2.2.1 基本知识
需要下载安装后才能导入使用
-
安装方式:
- pip包管理工具
# 把pip.exe 所在的目录添加到环境变量中。 pip install 要安装的模块名称 # pip install xlrd
- 源码安装
# 下载源码包(压缩文件) -> 解压 -> 打开cmd窗口,并进入此目录:cd C:\Python37\Lib\site-packages # 执行:python3 setup.py build # 执行:python3 setup.py install
安装路径:C:\Python37\Lib\site-packages
6.2.2.2 常用的第三方模块
- requests
- xlrd
6.2.3 自定义模块
-
自己写的 xx.py
def f1(): print('f1') def f2(): print('f2')
-
在yy.py中调用
# 调用自定义模块中的功能 import xx xx.f1() xx.f2()
-
运行
python yy.py
6.3 模块的调用
注意:文件和文件夹的命名不能是导入的模块名称相同,否则就会直接在当前目录中查找
6.3.1 绝对导入
1.模块的基本导入及调用
导入XXX.py文件
方式一
# 导入模块,加载此模块中所有的值到内存。
import XXX
# 调用模块中的函数
XXX.func()
- 方式二
# 导入XXX.py中的func和show
from XXX import func,show
# 导入XXX.py中的所有值
from XXX import *
# 调用模块中的函数
func()
- 方式三
# 如果有重名情况,就导入时起一个别名
# 导入XXX.py中的func,并起一个别名为f
from XXX import func as f
# 调用模块中的函数
f()
- 总结
- 导入:import 模块,调用:模块.函数()
- 导入:from 模块 import 函数,调用:函数()
- 导入:from 模块 import 函数 as 别名,调用:别名()
- 知识点:
- as:起别名
- *:代表全部
-
补充
-
多次导入不再重新加载
import jd # 第一次加载:会加载一遍jd中所有的内容。 import jd # 由已经加载过,就不再加载。 print(456)
-
非要重新加载
import importlib import jd importlib.reload(jd) print(456)
-
- 导入文件夹中的py文件及调用
导入YYY文件夹中的XXX.py文件
方式一
# 导入模块
import YYY.XXX
# 调用模块中的函数
XXX.func()
- 方式二
# 导入模块
from YYY import XXX
# 调用模块中的函数
XXX.func()
- 方式三
# 导入模块
from YYY.XXX import func
# 调用模块中的函数
func()
- 总结
- 模块和要执行的py文件在同一目录 且 需要 模块中的很多功能时,推荐用:
- 导入:import 模块,调用:模块.函数()
- 其他推荐:
- 导入:from 模块 import 模块,调用:模块.函数()
- 导入:from 模块.模块 import 函数,调用:函数()
6.3.2 相对导入(不推荐)
from . import xxx
from .. import xxx
第七章 面向对象
7.1 面向对象的基本知识
7.1.1 基本格式
# 定义类
class 类名:
def 方法名(self,name):
print(name)
return 123
def 方法名(self,name):
print(name)
return 123
def 方法名(self,name):
print(name)
return 123
# 调用类中的方法
# 1.创建该类的对象
obj = 类名()
# 2.通过对象调用方法
result = obj.方法名('alex')
print(result)
7.1.2 应用场景
- 应用场景:遇到很多函数,需要给函数进行归类和划分
- 补充:
- 类和对象是什么关系?
- 对象是类的一个实例
- self是什么?
- self就是一个形式参数,对象调用方法时,python内部会将该对象传给这个参数
- 类内部代码会从上到下依次执行,类变量立即执行,方法需调用内部代码才会执行
- 类与类之间可以嵌套,执行遵循上条
- 什么时候用面向对象?
- 函数(业务功能)比较多,可以使用面向对象来进行归类
- 想要做数据封装(创建字典存储数据时,面向对象)
- 游戏示例:创建一些角色并且根据角色需要再创建人物
- 类和对象是什么关系?
7.2 面向对象的三大特性
7.2.1 封装
-
对象的作用:存储一些值,以后方便自己使用
class File: def read(self): with open(self.xxxxx, mode='r', encoding='utf-8') as f: data = f.read() return data def write(self, content): with open(self.xxxxx, mode='a', encoding='utf-8') as f: f.write(content) # # 实例化了一个File类的对象 obj1 = File() # # 在对象中写了一个xxxxx = 'test.log' obj1.xxxxx = "test.log" # # 通过对象调用类中的read方法,read方法中的self就是obj。 # # obj1.read() obj1.write('alex') # 实例化了一个File类的对象 obj2 = File() # 在对象中写了一个xxxxx = 'test.log' obj2.xxxxx = "info.txt" # 通过对象调用类中的read方法,read方法中的self就是obj。 # obj2.read() obj2.write('alex')
-
封装的作用:将数据封装到对象,方便使用
class Person: def __init__(self,n,a,g): # 初始化方法(构造方法),给对象的内部做初始化。 self.name = n self.age = a self.gender = g def show(self): temp = "我是%s,年龄:%s,性别:%s " % (self.name, self.age, self.gender,) print(temp) # 类() 实例化对象,自动执行此类中的 __init__方法。 p1 = Person('李兆琪',19,'男') p1.show() p2 = Person('利奇航',19,'男') p2.show()
-
总结
- 如果写代码时,函数比较多比较乱
可以将函数归类并放到同一个类中
函数如果有一个反复使用的公共值,则可以放到对象中
# 示例:循环让用户输入:用户名/密码/邮箱。 输入完成后再进行数据打印。 # 以前的写法: USER_LIST = [] while True: user = input('请输入用户名:') pwd = input('请输入密码:') email = input('请输入邮箱:') temp = {'username':user,'password':pwd,'email':email} USER_LIST.append(temp) for item in USER_LIST: temp = "我的名字:%s,密码:%s,邮箱%s" %(item['username'],item['password'],item['email'],) print(temp) # 面向对象写法一: class Person: def __init__(self,user,pwd,email): self.username = user self.password = pwd self.email = email USER_LIST = [对象(用户/密码/邮箱),对象(用户/密码/邮箱),对象(用户/密码/邮箱)] while True: user = input('请输入用户名:') pwd = input('请输入密码:') email = input('请输入邮箱:') p = Person(user,pwd,email) USER_LIST.append(p) for item in USER_LIST: temp = "我的名字:%s,密码:%s,邮箱%s" %(item.username,item.password,item.email,) print(temp) # 面向对象写法二: class Person: def __init__(self,user,pwd,email): self.username = user self.password = pwd self.email = email def info(self): return "我的名字:%s,密码:%s,邮箱%s" %(item.username,item.password,item.email,) USER_LIST = [对象(用户/密码/邮箱),对象(用户/密码/邮箱),对象(用户/密码/邮箱)] while True: user = input('请输入用户名:') pwd = input('请输入密码:') email = input('请输入邮箱:') p = Person(user,pwd,email) USER_LIST.append(p) for item in USER_LIST: msg = item.info() print(msg)
- 如果写代码时,函数比较多比较乱
7.2.2 继承
-
基本内容
# 父类(基类) class Base: def f1(self): pass # 子类(派生类) class Foo(Base): def f2(self): pass # 创建了一个子类的对象 obj = Foo() # 执行对象.方法时,优先在自己的类中找,如果没有就是父类中找 obj.f2() obj.f1() # 创建了一个父类的对象 obj = Base() obj.f1()
-
总结
- 什么时候才能用到继承?
- 多个类中如果有公共的方法,可以放到基类中避免重复编写
- 继承关系中的查找方法的顺序时,注意事项:
- self 到底是谁?
- self 是哪个类创建的,就从此类开始找,自己没有就找父类
- 多继承,如果一个派生类有多个基类,执行对象.方法时,优先在自己的类中找,如果没有,就从左到右依次从基类中找
- 什么时候才能用到继承?
-
补充(python2与python3的区别十一):
class Foo: pass class Foo(object): pass # 在python3中这俩的写法是一样,因为所有的类默认都会继承object类,全部都是新式类。 # 如果在python2中这样定义,则称其为:经典类 class Foo: pass # 如果在python2中这样定义,则称其为:新式类 class Foo(object): pass
7.2.3 多态
-
基本内容:多种形态/多种类型,python本身就是多态的
def func(arg): # 多种类型,很多事物 arg.send() # 必须具有send方法,呱呱叫
-
面试题:什么是鸭子模型?
对于一个函数而言,Python对于参数的类型不会限制,那么传入参数时就可以是各种类型,在函数中如果有例如:arg.send方法,那么就是对于传入类型的一个限制(类型必须有send方法),这就是鸭子模型
类似于上述的函数我们认为只要能呱呱叫的就是鸭子(只有有send方法,就是我们想要的类型)
7.3 成员
7.3.1 类成员
-
类变量(静态字段)
- 定义:写在类的下一级,和方法同一级
- 访问:
- 类.类变量名()
- 对象.类变量名()
- 注意:如果对象中也有同名变量,则对象.类变量名()使用对象自己中的变量
# 面试题 class Base: x = 1 obj = Base() print(obj.x) # 先去对象中找,没有再去类中找 obj.y = 123 # 在对象中添加了一个y=123的变量 obj.x = 123 # 在对象中添加了一个X=123的变量,无法修改类变量 Base.x = 666 # 修改类变量,x = 666
- 总结:
- 找变量优先找自己,自己没有找类或基类
- 修改或赋值只能在自己的内部设置
-
绑定方法(普通方法)
- 定义:至少有一个self参数
- 执行:先实例化对象,对象.绑定方法名()
class Foo: def __init__(self): self.name = 123 def func(self, a, b): print(self.name, a, b) obj = Foo() obj.func(1, 2)
-
静态方法
- 定义:
- @staticmethod装饰器
- 参数无限制
- 执行:
- 类.静态方法名()【推荐】
- 对象.静态方法名()【不推荐,容易混淆】
class Foo: def __init__(self): self.name = 123 @staticmethod def f1(): print(123) obj = Foo() Foo.f1() obj.f1() # 不推荐
- 定义:
-
类方法
- 定义:
- @classmothod装饰器
- 至少有cls参数(cls是当前类)
- 执行:
- 类.类方法名()【推荐】
- 对象.类方法名()【不推荐,容易混淆】
class Foo: def __init__(self): self.name = 123 @classmethod def f2(cls,a,b): print('cls是当前类',cls) print(a,b) obj = Foo() Foo.f2(1,2) obj.f2(1,2) # 不推荐
- 面试题(笔试)
- 问: @classmethod和@staticmethod的区别?
- 答:一个是类方法,一个静态方法
定义:
类方法:用@classmethod做装饰器且至少有一个cls参数
静态方法:用staticmethod做装饰器且参数无限制
调用:
类.方法直接调用,对象.方法也可以调用
- 定义:
-
属性
- 定义:
- @property
- 只能有一个self参数
- 执行:
- 对象.方法名
- 后面不用加括号
class Foo: @property def func(self): print(123) return 666 obj = Foo() result = obj.func print(result)
- 应用:
# 属性的应用 class Page: def __init__(self, total_count, current_page, per_page_count=10): self.total_count = total_count self.per_page_count = per_page_count self.current_page = current_page @property def start_index(self): return (self.current_page - 1) * self.per_page_count @property def end_index(self): return self.current_page * self.per_page_count USER_LIST = [] for i in range(321): USER_LIST.append('alex-%s' % (i,)) # 请实现分页展示: current_page = int(input('请输入要查看的页码:')) p = Page(321, current_page) data_list = USER_LIST[p.start_index:p.end_index] for item in data_list: print(item)
- 定义:
7.3.2 实例(对象)成员
7.3.2.1 实例成员:实例变量
7.3.2.2 实例(对象)之间的嵌套
- 函数:参数可以是任意类型
- 字典:对象和类都可以做字典的key和value
-
示例:
class School(object): def __init__(self,title,addr): self.title = title self.address = addr class ClassRoom(object): def __init__(self,name,school_object): self.name = name self.school = school_object s1 = School('北京','沙河') s2 = School('上海','浦东') s3 = School('深圳','南山') c1 = ClassRoom('全栈21期',s1) c1.name c1.school.title c1.school.address
class StackConfig(object): list_display = '李邵奇' def changelist_view(self): print(self.list_display) class UserConfig(StackConfig): list_display = '利奇航' class AdminSite(object): def __init__(self): self._register = {} def registry(self,key,arg=StackConfig): self._register[key] = arg def run(self): for key,value in self._register.items(): obj = value() obj.changelist_view() site = AdminSite() site.registry(1) site.registry(2,StackConfig) site.registry(3,UserConfig) site.run()
7.3.3 成员修饰符
公有,所有地方都能访问到
-
私有,只有自己可以访问到,修饰符:双下划线__
# 示例一: class Foo: def __init__(self, name): self.__name = name def func(self): print(self.__name) obj = Foo('alex') # print(obj.__name),报错,无法访问 obj.func() # 示例二: class Foo: __x = 1 @staticmethod def func(): print(Foo.__x) # print(Foo.__x),报错,无法访问 Foo.func() # 示例三: class Foo: def __fun(self): print('msg') def show(self): self.__fun() obj = Foo() # obj.__fun(),报错,无法访问 obj.show()
-
强制访问私有,中间加上_类名
class Foo: def __init__(self,name): self.__x = name obj = Foo('alex') print(obj._Foo__x) # 强制访问私有实例变量
7.3.4 特殊成员
- 特殊成员:就是为了能够快速实现执行某些方法而生
7.3.4.1 __init__
- 初始化方法
- 用途:用于给对象中赋值
class Foo:
def __init__(self,a1):
self.a1 = a1
obj = Foo('alex')
7.3.4.2 __new__
- 构造方法
- 用于创建空对象
class Foo(object):
def __init__(self):
self.x = 123
def __new__(cls, *args, **kwargs):
return object.__new__(cls)
obj = Foo() # 先执行__new__方法,再执行__init__方法
7.3.4.3 __call__
- 对象后面加括号执行该方法
class Foo(object):
def __call__(self, *args, **kwargs):
print('执行call方法')
obj = Foo()
obj() # 对象后面加括号,执行__call__方法
# 相当于Foo()()
- 网站示例:
from wsgiref.simple_server import make_server
def func(environ,start_response):
start_response("200 OK", [('Content-Type', 'text/plain; charset=utf-8')])
return ['你好'.encode("utf-8") ]
class Foo(object):
def __call__(self, environ,start_response):
start_response("200 OK", [('Content-Type', 'text/html; charset=utf-8')])
return ['你<h1 style="color:red;">不好</h1>'.encode("utf-8")]
# 作用:写一个网站,用户只要来方法,就自动找到第三个参数并执行。
server = make_server('127.0.0.1', 8000, Foo())
server.serve_forever()
7.3.4.4 __getitem__ __setitem__ __delitem__
class Foo(object):
def __setitem__(self, key, value):
pass
def __getitem__(self, item):
return 'uuu'
def __delitem__(self, key):
pass
obj1 = Foo()
obj1['k1'] = 123 # 内部会自动调用 __setitem__方法
val = obj1['xxx'] # 内部会自动调用 __getitem__方法,用val接受返回值
del obj1['ttt'] # 内部会自动调用 __delitem__ 方法
7.3.4.5 __str__
- 只有在打印对象时,会自动化调用此方法,并将其返回值在页面显示出来
class Foo(object):
def __str__(self):
return 'asdfasudfasdfsad'
obj = Foo()
print(obj) # obj是一个对象,打印__str__方法的返回值
- 示例:
class User(object):
def __init__(self,name,email):
self.name = name
self.email = email
def __str__(self):
return "%s %s" %(self.name,self.email,)
user_list = [User('二狗','2g@qq.com'),User('二蛋','2d@qq.com'),User('狗蛋','xx@qq.com')]
for item in user_list:
print(item)
7.3.4.6 __dict__
- 去对象中找到所有变量并将其转换为字典
class Foo(object):
def __init__(self,name,age,email):
self.name = name
self.age = age
obj = Foo('alex',19)
val = obj.__dict__ # 去对象中找到所有变量并将其转换为字典
print(val)
7.3.4.7 __enter__ __exit__
- 上下文管理
# 面试题
class Foo(object):
def do_something(self):
print('内部执行') # 第三步
class Context:
def __enter__(self):
print('进入') # 第一步
return Foo()
def __exit__(self, exc_type, exc_val, exc_tb):
print('推出') # 第四步
with Context() as ctx:
print('内部执行') # 第二步
ctx.do_something()
7.3.4.8 __add__
- 两个对象相加时用到此方法
class Foo(object):
def __add__(self, other): # self:obj1,other:obj2
return 123
obj1 = Foo()
obj2 = Foo()
val = obj1 + obj2 # 内部会自动调用 __add__方法,并用val接受返回值
print(val) # 123
7.3.4.9 __iter__
- 将一个对象变成可迭代对象时用到此方法
class Foo:
def __iter__(self):
return iter([1,2,3,4])
obj = Foo()
7.4 数据结构
7.4.1 队列
- 先进先出
7.4.2 栈
-
后进先出
class Stack(object): """ 后进先出 """ def __init__(self): self.data_list = [] def push(self, val): """ 向栈中压入一个数据(入栈) """ self.data_list.append(val) def pop(self): """ 从栈中拿走一个数据(出栈) """ return self.data_list.pop()
7.5 约束
-
示例
# 约束子类中必须写send方法,如果不写,则调用时候就报抛出 NotImplementedError class BaseMessage(object): def send(self,a1): raise NotImplementedError('子类中必须有send方法') class Msg(BaseMessage): def send(self): pass class Email(BaseMessage): def send(self): pass class DingDing(BaseMessage): def send(self): print('钉钉') obj = Email() obj.send()
7.6 反射
- 根据字符串的形式去某个对象中操作他的成员
7.6.1 getattr(对象,字符串)
-
根据字符串的形式去某个对象中获取该成员
class Foo(object): def __init__(self,name): self.name = name obj = Foo('alex') # 获取变量 v1 = getattr(obj,'name') # 获取方法 method_name = getattr(obj,'login') method_name()
-
补充:
class Foo(object): def get(self): pass obj = Foo() # if hasattr(obj,'post'): # getattr(obj,'post') v1 = getattr(obj,'get',None) # 推荐 print(v1)
7.6.2 hasattr(对象,字符串)
-
根据字符串的形式去某个对象中判断是否有该成员
from wsgiref.simple_server import make_server class View(object): def login(self): return '登陆' def logout(self): return '等处' def index(self): return '首页' def func(environ,start_response): start_response("200 OK", [('Content-Type', 'text/plain; charset=utf-8')]) obj = View() # 获取用户输入的URL method_name = environ.get('PATH_INFO').strip('/') if not hasattr(obj,method_name): return ["sdf".encode("utf-8"),] response = getattr(obj,method_name)() return [response.encode("utf-8") ] # 作用:写一个网站,用户只要来方法,就自动找到第三个参数并执行。 server = make_server('192.168.12.87', 8000, func) server.serve_forever()
7.6.3 setattr(对象,字符串,值)
-
根据字符串的形式去某个对象中设置/修改该成员
class Foo: pass obj = Foo() obj.k1 = 999 setattr(obj,'k1',123) # obj.k1 = 123 print(obj.k1)
7.6.4 delattr(对象,字符串)
-
根据字符串的形式去某个对象中删除该成员
class Foo: pass obj = Foo() obj.k1 = 999 delattr(obj,'k1') print(obj.k1)
7.6.5 python一切皆对象
- 对象的定义
- 狭义:类实例化出来的就是对象
- 广义:
- 模块(py文件)及其内部成员
- 包(文件夹)及其内部成员
- 类及其内部成员
- 狭义的对象
- python一切皆对象,所以以后想要通过字符串的形式操作其内部成员都可以通过反射的机制实现
7.7 单例模式(23种设计模式)
定义:无论实例化多少次,永远用的都是第一次实例化出的对象
应用场景:数据库连接,数据库连接池
-
单例模式标准
class Singleton(object): instance = None def __new__(cls, *args, **kwargs): if not cls.instance: cls.instance = object.__new__(cls) return cls.instance obj1 = Singleton() obj2 = Singleton() # 不是最终,加锁。
- 文件的连接池
class FileHelper(object): instance = None def __init__(self, path): self.file_object = open(path,mode='r',encoding='utf-8') def __new__(cls, *args, **kwargs): if not cls.instance: cls.instance = object.__new__(cls) return cls.instance obj1 = FileHelper('x') obj2 = FileHelper('x')
-
通过模块导入的特性也可以实现单例模式:
# jd.py class Foo(object): pass obj = Foo()
# app.py import jd # 加载jd.py,加载最后会实例化一个Foo对象并赋值给obj print(jd.obj)
7.8 项目结果目录
7.8.1 项目分类
脚本:把所有代码写在一个py文件中
-
单可执行文件:只有一个可执行文件
# 可执行文件中包含: if __name__ == '__main__': pass
多可执行文件:有多个可执行文件
7.8.2 项目目录
-
包及其内含文件示例
- 可执行文件:bin
- 将所有可执行文件放入其中
- 业务相关:src
- 登陆注册相关:account.py
- 订单相关:order.py
- 主程序:run.py
- 公共类库:lib
- 分页功能
- 数据库:db
- 用户资料:user.txt
- 配置:config
- 设置:setting.py
- 日志存储:log
- 所有的日志文件
- 可执行文件:bin
-
注意:每个可执行文件必须把项目根目录加入sys.path中
import os import sys BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR)
第八章 网络编程
第九章 并发编程
第十章 数据库
第十一章 前端开发
第十二章 Django框架
附录
1.异常处理
1.1 基本格式
# 示例一:
import requests
try: # 尝试进行下面操作,如果可以执行,就执行下面代码
ret = requests.get('http://www.google.com')
print(ret.text)
except Exception as e: # 如果不可以执行(平时会报错),这时不会报错,执行下面代码
print('请求异常')
# 示例二:
try:
v = []
v[11111] # IndexError类型的异常
except ValueError as e: # ValueError是一个类,继承Exception,只能捕获到ValueError类型的异常
pass
except IndexError as e: # IndexError是一个类,继承Exception,只能捕获到IndexError类型的异常
pass
except Exception as e: # Exception是一个类,可以捕获到所有异常
print(e) # e是Exception类的对象,存储了一个错误信息
-
finally
try: int('asdf') except Exception as e: print(e) finally: print('最后无论对错都会执行') # 特殊情况: def func(): try: int('asdf') except Exception as e: return 123 finally: print('最后') # 无论对错,函数中遇到return,也会执行,执行完后再return func()
建议:书写函数或功能时,建议用try包裹一下,避免报错
-
示例
# 1. 写函数,函数接受一个列表,请将列表中的元素每个都 +100 def func(arg): result = [] for item in arg: if item.isdecimal(): result.append(int(item) + 100) return result # 2. 写函数去,接受一个列表。列表中都是url,请访问每个地址并获取结果 import requests def func1(url_list): result = [] try: for url in url_list: response = requests.get(url) result.append(response.text) except Exception as e: pass return result def func2(url_list): result = [] for url in url_list: try: response = requests.get(url) result.append(response.text) except Exception as e: pass return result # 这两个函数执行结果是不一样的,是try所处的位置不同导致的 func1(['http://www.baidu.com','http://www.google.com','http://www.bing.com']) func2(['http://www.baidu.com','http://www.google.com','http://www.bing.com'])
1.2 主动触发异常
try:
int('123')
raise Exception('XXX') # 代码中主动抛出异常
except Exception as e:
print(e) # XXX
-
示例:
def func(): result = True try: with open('x.log',mode='r',encoding='utf-8') as f: data = f.read() if 'alex' not in data: raise Exception() except Exception as e: result = False return result
1.3 自定义异常
class MyException(Exception): # 自定义异常,继承Exception
pass
try:
raise MyException('asdf') # 主动触发自定义异常,只有自定义异常自己和Exception能捕获到
except MyException as e:
print(e)
2.单词
单词 | 含义 | 补充 |
---|---|---|
输出 | ||
input | 输入 | |
True | 正确 | 布尔值 |
False | 错误 | 布尔值 |
pass | 跳过,通过 | |
break | 终止 | |
continue | 继续 | |
if / elif | 如果 | 条件语句 |
else | 其他 | |
while | 当......的时候 | while循环 |
for | for循环 | |
upper | 小写变为大写 | 字符串方法 |
lower | 大写变为小写 | 字符串方法 |
isdecimal | 判断是否为数字 | 字符串方法:isdigit类似 |
strip / rstrip / lstrip | 去空格/去换行符/去制表符/去除指定的字符串 | 字符串方法 |
replace | 替换 | 字符串方法 |
split / rsplit | 切割 | 字符串方法 |
len | 计算长度 | 公共功能 |
startswith / endswith | 判断是否已......开头/结尾 | 字符串方法 |
format | 字符串格式化 | 字符串方法 |
encode | 将unicode转换成其他编码存储 | 字符串方法 |
join | 循环每个元素,并在元素和元素之间加入连接符 | 字符串方法 |
range | 用于for循环 | |
append | 追加 | 列表方法 |
insert | 插入 | 列表方法 |
remove | 删除(指定元素) | 列表方法 |
pop | 删除(索引位置的元素) | 列表方法,字典方法 |
clear | 删除全部 | 列表方法 |
del | 删除 | 公共功能 |
extend | 循环加入 | 列表方法 |
keys | 获取字典中的所有键 | 字典方法 |
values | 获取字典中的所有值 | 字典方法 |
items | 获取字典中的所有键值对 | 字典方法 |
reverse | 反转 | 列表方法 |
sort | 排序 | 列表方法 |
get | 相当于索引取值 | 字典方法 |
update | 批量添加(修改):不存在则添加,存在则修改 | 字典方法,集合方法 |
add | 添加 | 集合方法 |
discard | 删除 | 集合方法 |
intersection | 交集 | 集合方法 |
union | 并集 | 集合方法 |
different | 差集 | 集合方法 |
symmetric_different | 对称差集 | 集合方法 |
def | 函数 | |
return | 返回值 | 函数中使用 |
argument | 参数 | 函数中使用 |
*args | 万能参数(最终转化为元组,只能使用位置传参) | 函数中使用 |
**kwargs | 万能参数(最终转化为字典,只能使用关键字传参) | 函数中使用 |
global | 直接找到全局的变量 | 用于子作用域对全局变量重新赋值 |
nonlocal | 只找到 '父级' 的变量 | 用于子作用域对 '父级' 变量重新赋值 |
lambda | lambda表达式 | 用于表示简单的函数 |
abs() | 计算绝对值 | 内置函数 |
sum() | 内置函数 | |
float() | 转换成浮点型 | 内置函数 |
max() | 找到最大值 | 内置函数 |
min() | 找到最小值 | 内置函数 |
divmod() | 取两数相除的商和余数 | 内置函数 |
bin() | 将十进制转换成二进制 | 内置函数 |
oct() | 将十进制转换成八进制 | 内置函数 |
int() | 将其他进制转换成十进制 | 内置函数 |
hex() | 将十进制转换成十六进制 | 内置函数 |
base | 说明读取的进制种类,再将其转化为十进制 | 将其他进制转换成十进制时使用 |
pow() | 指数 | 内置函数 |
round() | 保留几位小数 | 内置函数 |
chr() | 将十进制数字转换成 unicode 编码中的对应字符串 | 内置函数 |
ord() | 根据字符在 unicode 编码中找到其对应的十进制 | 内置函数 |
map() | 一起执行 | 内置函数 |
filter() | 进行筛选 | 内置函数 |
reduce() | 得到结果 | 内置函数 |
import | 导入模块 | |
random | 随机数模块 | 内置模块 |
random.randint(a,b) | 得到一个随机数 | random模块 |
hashlib | 加密模块 | 内置模块 |
hashlib.md5() | md5 加密函数 | hashlib模块 |
getpass | 输入密码隐藏,只能在终端运行 | 内置模块 |
getpass.getpass | 输入密码时不显示 | getpass模块 |
sys | python解释器相关数据 | 内置模块 |
sys.getrefcount | 获取一个值的应用计数 | sys模块 |
sys.getrecursionlimit | python默认支持的递归数量 | sys模块 |
sys.stdout.write | 输入输出 | sys模块 |
sys.argv | 获取用户执行脚本时,传入的参数 | sys模块 |
sys.exit(0) | 程序终止,0代表正常终止 | sys模块 |
sys.path | 默认python去导入模块时,会按照sys.path中的路径 | sys模块 |
time | 时间模块 | 内置模块 |
time.time | 获取当前时间(从1970年到现在经历的秒数) | time模块 |
time.sleep | 暂停几秒 | time模块 |
os | 和操作系统相关的数据 | 内置模块 |
os.path.exists(path) | 如果path存在,返回True;否则,返回False | os模块 |
os.stat(path).st_size | 获取文件大小 | os模块 |
os.path.abspath() | 获取一个文件的绝对路径 | os模块 |
os.path.dirname() | 获取路径的上级目录 | os模块 |
os.path.join | 路径的拼接 | os模块 |
os.listdir | 查看一个目录下所有的文件【第一层】 | os模块 |
os.walk | 查看一个目录下所有的文件【所有层】 | os模块 |
os.makedirs | 创建目录及其子目录 | os模块 |
os.rename | 重命名 | os模块 |
shutil | 删除/解压模块 | 内置模块 |
shutil.rmtree(path) | 删除文件 | shutil模块 |
json | 一个特殊的字符串 | 内置模块 |
json.dumps() | 序列化 | json模块 |
json.loads() | 反序列化 | json模块 |
3.错误记录
- 缩进错误
- 键错误