python基础
基本输出
python字符串格式化输出有三种方式: %、format、f
%
打印用户信息
name = 'acai'
age = 27
addr = 'BeiJing'
print("My name is %s, age: %s address: %s" %(name,age,addr))
使用字典传值方式,打破位置的限制
temp = '教程是:%(name)s, 价格是:%(price)010.2f, 出版社是:%(publish)s'
book = {'name':'Python基础教程', 'price': 99, 'publish': 'C语言中文网'}
print(temp % book)
format
打印用户信息
res = "name: {0}, age: {1}, addr: {2}".format('acai',27,'beijing')
print(res)
打破位置的限制,安装key=value传值
res = "name: {name}, age: {age}, addr: {addr}".format(name='acai',age=27,addr='beijing')
print(res)
f
在python3.5之后版本支持,效率要高于%、format
name='acai'
age=27
res = f"name:{name}, age:{age}"
print(res)
基本输入
python中使用input()函数将用户输入的数据存储,在python2中raw_input和python3 input功能一样,都会返回字符串类型数据;python2中input,用户输入什么类型数据python就会返回什么类型数据。
例如:
username = input("please input your name:")
print(username)
字符编码
unicode作用?
用来作为其他编码的中转,比如:
utf-8 转 gbk:
utf-8 > unicode >gbk
文件存取乱码问题?
存乱了:解决方式是,编码格式应该设置成支持文件字符串格式
取乱了:解决方式是,文件是以什么编码格式存入硬盘的,就应该以什么编码格式读入内存
python解释器默认读文件编码格式?
python3默认,utf-8
python2默认,ascii
python3 str类型默认直接存成unicode格式,为了保证python2 str类型不乱码,将字符串转unicode,例如:
x = u"阿才"
python文件指定默认编码?
#coding:utf-8
编码与解码?
编码:其他编码转unicode,encode()
解码:unicode转其他编码,decode()
示例:
unicode转gbk,编码:
s = '阿才的博客'
res = s.encode('gbk')
print(res,type(res))
gbk转unicode,解码:
s = '阿才的博客'
res = s.encode('gbk')
print(res.decode('gbk'))
变量
什么是变量?
变量就是可以变化的量,量指的是食物的状态。比如人的姓名、年龄、性别等。
为什么要有变量?
通俗的讲:为了让计算机能够想人一样去记忆事务的某种状态,并且状态是可以发生变化的。 简单来说:程序执行的本质就是一系列状态的变化,变是程序执行的直接体现。所以我们需要有一种机制能够反映
变量的定义?
定义变量
name = 'acai.cloud'
引用变量
print(name)
变量三大组成部分?
变量名:是指向等号右侧值的内存地址,用来访问右侧的值 赋值符号:将变量值的内存地址绑定给变量名 变量值:代表记录的事物状态
变量命令规则?
变量名只能是字母、数字、或者下划线的任意组合 变量名的第一个字符不能是数字 不能使用python内置关键字
变量命令规范?
纯小写加下划线的方式
变量值三个重要特征?
变量值的ID: 反映的事变量值的内存地址 变量的type:不同类型的值用来表示记录不同的状态 变量的value: 值本身
获取变量的id,例如:
name = 'acai'
print id(name)
获取变量的type,例如:
print (type(name))
获取变量的value,例如:
print (name)
变量的is与==
is: 比较左右两个变量值ID是否相等
x = 10
y = x
print (x is y)
==:比较左右两个值他们的值是否相等
常量
常量:代表不变的量 小写字母全为大写代表常量,这只是一种约定、规范
数据类型
字符串 str
定义:用来定义字符串类型数据
name = 'acai.cloud'
or
name = "acai.cloud"
内置方法
备注:
strip():
默认移除空格,strip只移除两边,不移除中间;strip把字符串转换为列表
split():
把一个字符串按照某种分隔符进行切分,得到一个列表;split默认分隔符是空格
示例:
msg = 'acai.cloud'
| 名称 | 参考代码 |
|---|---|
| 正向取值,取第一个字符 | msg[0] |
| 反向取值,取最后一个字符 | msg[-1] |
| 获取前三个字符串 | msg[0:3] |
| 获取后三个字符串 | |
| 取0~5个字符串,步长为2(取相隔第二个字符串) | msg[0:5:2] |
| 从后往前取0~5个字符串,步长为2 | msg[5:0:-2] |
| 转换字符串顺序 | msg[::-1] |
| 获取字符串长度 | len(msg) |
| 判断字符串是否存在于msg | "a" in msg |
| 判断字符串不存在于msg | 'b' not in msg |
| 删除字符串左右两侧空格 | msg.strip() |
| 删除字符串左右两侧"," | msg.strip(',') |
| 删除左边字符串 | msg.lstrip('=') |
| 删除右边字符串 | msg.rstrip('=') |
| 把字符串按照空格为分隔符,返回一个列表 | info.split() |
| split指定分隔符(从左向右切分) | info.split(':') |
| split指定分割次数(从左向右切分) | info.split(':',1) |
| 从右往左切分 | msg.rsplit(':',1) |
| 字符串转换为小写 | msg.lower() |
| 字符串转换为大写 | msg.upper() |
| 判断以字符串开始 | msg.startswith('acai') |
| 判断以字符串结尾 | msg.endswith('blog') |
| 按照某个分隔符号,把元素为全部是字符串的列表拼接为字符串 | ":".join(list1) |
| 替换 | msg.replace("NB","super NB") |
| 判断字符串是否由数字组成 | msg.isdigit() |
| 判断字符串全部小写 | msg.islower() |
| 判断字符串全部大写 | 'ACAI'.isupper() |
| 判断字符串由字母或数字组成 | 'acai123'.isalnum() |
| 判断字符串由字母组成 | 'acai'.isalpha() |
| 判断字符串由空格组成 | ' '.isspace() |
整型 int
定义:用来定义整数(自然数)类型数据
age = 27
纯数字字符串转换为整型
print(int("123"))
浮点型 float
定义:用来定义小数类型数据
aaa = 3.1314
字符串小数转换为float类型
print(float("3.1"))
列表 list
作用?
按位置存多个值的数据类型,列表属于有序类型数据
定义?
在[]中用逗号分隔,多个任意类型的值,例如:
list1 = [1,2,3,4,5,6]
print(list1)
列表内置方法?
示例:
list1 = [1,2,3,4]
| 名称 | 参考代码 |
|---|---|
| 字符串转列表 | list('acaiblog') |
| 字典转换为列表 | list({'name':'acai', 'age':27, 'addr':'beijing'}) |
| 正向取值 | [1,2,3][0] |
| 反向取值 | [1,2,3][-1] |
| 修改列表索引对应值 | list1[2] = 4 |
| 列表添加元素 | list1.append(5) |
| 列表插入元素 | list1.insert(1,'acaiblog') |
| 删除列表元素,根据索引删除 | list1.pop(0) |
| 删除列表元素(根据列表元素删除) | list1.remove(2) |
| 统计列表元素个数 | list1.count(2) |
| 根据列表索引查值 | list1.index(1) |
| 清空列表所有元素 | list1.clear() |
| 将列表元素顺序反转 | list1.reverse() |
| 列表元素排序(默认从小到大) | list1.sort() |
| 列表元素排序(从大到小) | list1.sort(reverse=True) |
元组 tuple
作用?
按照索引存放多个值,只能用于读不能修改
特点?
元组是一个不可变的列表
定义?
()内用逗号分隔开多个任意类型的元素;如果元组中只有一个元素必须加逗号
内置方法?
示例:
tup1 = (1,2,3,4)
| 名称 | 方法 |
|---|---|
| 字符串转换为元组 | tuple(str("acaicloud")) |
| 列表转换为元组 | tuple(list([1,2,3,4])) |
| 字典转换为元组(默认会将字典key转换为元组) | tuple({"name": "acai", "age":27, "addr":"BeiJing"}) |
| 按照索引取值 | tup1[0] |
| 按照索引反向取值 | tup1[-1] |
| 反向获取元组所有元素 | tup1[::-1] |
| 获取元组长度 | len(tup1) |
| 统计元素有几个 | tup1.count(1) |
| 获取元组索引 | tup1.index(1) |
字典 dict
定义?
{}内逗号分隔开多个key:value对应值,其中value可以是任意类型;但是key必须是不可变类型且不可重复
内置方法?
示例:
dict1 = {"name":"acai.cloud", "age":27}
重点:
列表转换为字典:列表转字典可以将一个列表中第一个元素作为字典key,第二个元素作为字典value
通过列表快速初始化一个字典: key为列表元素,value为默认值None;value可以为任意数据类型
| 名称 | 方法 |
|---|---|
| 定义字典 | dict1 = dict() |
| 列表转换为字典 | dict([['name','acaiblog'],['age',27]]) |
| 通过列表快速初始化一个字典 | info = ['name', 'age', 'addr']; print({}.fromkeys(info,None)) |
| 通过key获取value值 | dict1['name'] |
| 赋值操作,如果key存在则修改否则创建 | dict1['name'] = 'acai.cloud' |
| pop删除,根据key删除;该key的value值 | dict1.pop('name') |
| popitem删除,随机删除,返回元组 | dict1.popitem() |
| 获取字典keys | dict1.keys() |
| 获取字典value | dict1.values() |
| 清空字典 | dict1.clear() |
| 获取字典key对应value,如果key不存在返回None | dict1.get('name') |
| 新字典更新旧字典 | dict1.update({'name':'acaiblog','age':28}) |
设置key对应value默认值,如果key不存在创建key并设置value为None | dict1.setdefault('addr') |
集合 set
定义?
定义空集合使用s=set(),如果使用s={}默认是空字典,因为字典和集合都是用{}定义数据的
定义一个空集合?
s1 = set()
print(s1,type(s1))
集合特征?
- 集合元素必须为不可变类型数据
- 集合内元素无序
- 集合内元素没有重复
定义一个集合?
s1 = {1,2,3,4}
print(s1,type(s1))
集合的用途?
- 关系运算
- 去重
集合关系运算?
交集
s1 = {1,2,3,4}
s2 = {2,4,6,8}
print(s1 & s2)
s1 = {1,2,3,4}
s2 = {2,4,6,8}
print(s1.intersection(s2))
并集
s1 = {1,2,3,4}
s2 = {2,4,6,8}
print(s1 | s2)
s1 = {1,2,3,4}
s2 = {2,4,6,8}
print(s1.union(s2))
差集:取s1的差集,s1相对比s2的差集
s1 = {1,2,3,4}
s2 = {2,4,6,8}
print(s1 - s2)
s1 = {1,2,3,4}
s2 = {2,4,6,8}
print(s1.difference(s2))
取对称差集:去掉两个集合共有元素
s1 = {1,2,3,4}
s2 = {2,4,6,8}
print(s1 ^ s2)
s1 = {1,2,3,4}
s2 = {2,4,6,8}
print(s1.symmetric_difference(s2))
子集:s1属于s2
s1 = {1,2,}
s2 = {1,2,4,6,8}
print(s1 < s2)
s1 = {1,2,}
s2 = {1,2,4,6,8}
print(s1.issubset(s2))
父集:s2包含s1
s1 = {1,2,}
s2 = {1,2,4,6,8}
print(s2 > s1)
s1 = {1,2,}
s2 = {1,2,4,6,8}
print(s2.issuperset(s1))
集合内置方法?
示例:
s1 = {1,2,3,4,5}
s2 = {10,11,12,14}
| 名称 | 方法 |
|---|---|
| discard: 删除元素,如果元素不存在不做任何事 | s1.discard(6) |
| remve: 删除元素,如果元素不存在返回异常 | s1.remove(6) |
| pop:删除元素,随机删除 | s1.pop() |
| add:添加元素 | s1.add(123) |
| isdisjoint: 判断两个集合完全独立(没有共同部分),返回True | s1.isdisjoint(s2) |
| 使用新集合更新旧集合:相当于s1 和s2并集,去重 | s1.update(s2) |
布尔类型 bool
作用:通常用来作判断的条件
数据类型总结
1.可变类型与不可变类型?
不可变数据类型:init、str、tuple
可变数据类型:set、list、dict
基本运算符
算数运算符
| 名称 | 示例 | 备注 |
|---|---|---|
| 加 | print(10 + 3) | 加法运算 |
| 减 | print(10 - 3) | 减法运算 |
| 乘 | print(10 * 3) | 乘法运算 |
| 除 | print(10 / 3) | 除法运算,结果带小数 |
| 地板除 | print(10 // 3) | 结果保留整数部分 |
| 取模 | print(10 ** 3) | 取余数 |
比较运算符
| 名称 | 示例 | 备注 |
|---|---|---|
| 大于 | ||
| 大于等于 | >= | |
| 小于 | < | |
| 小于等于 | <= | |
| 等于 | == | |
| 不等于 | != | |
逻辑运算符
| 名称 | 示例 | 备注 |
|---|---|---|
| 逻辑非 | not | not可以对符号右侧的值进行非运算; |
| 逻辑与 | and | |
| 逻辑或 | or |
逻辑运算符优先级:
not > and > or
成员运算符
| 名称 | 示例 | 备注 |
|---|---|---|
| 成员包含 | in | |
| 成员不包含 | not in |
身份运算符
| 名称 | 示例 | 备注 |
|---|---|---|
| 身份运算符 | is |
赋值运算符
变量赋值:
a = 1
增量赋值:
a = a + 1可以简写:
a += 1
链式赋值:
链式赋值:把一个变量值赋值给多个变量,例如:
z = y = z = 10
交叉赋值
把m赋值给n,把n赋值给m,例如:
n=10
m=20
m,n=n,m
print(m,n)
解压赋值
相当于把列表元素赋值给变量,例如:
list = [1,2,3,4]
a,b,c,d = list
print(a,b,c,d)
解压赋值中列表元素和变量要一一对应,如果变量不足可以用_代替,_无法取中间的值。例如:
list = [1,2,3,4]
a,b,c,*_ = list
print(a,b,c)
流程与控制
if条件判断
语法一:
if 条件:
代码1
语法二:
if 条件:
代码1
else:
代码2
语法三:
if 条件:
代码1
elif 条件:
代码2
语法四:
if 条件:
代码1
elif 条件:
代码2
else:
代码3
while循环
语法一:
while 条件:
代码1
语法二:
while 条件:
代码1
else:
代码2
while嵌套循环:
语法:
while 条件:
while 条件:
代码1
while退出循环python提供两种方式:while条件为假、break;
while条件为假和while + break方式的区别
- break:只要运行到break就会立刻终止本层循环
- while条件为假:判断条件为假时,会继续执行后面的代码直到循环结束
例如,while条件为假:
username = 'acai'
password = '123'
result = True
while result:
name = input("please input you username:")
pawd = input("please input you password:")
if name == username and pawd == password:
print("user {name} login sucessfully".format(name=name))
result = False
else:
print("user {name} login failed".format(name=name))
print("====end====")
例如,while + break方式:
username = 'acai'
password = '123'
while True:
name = input("please input you username:")
pawd = input("please input you password:")
if name == username and pawd == password:
print("user {name} login sucessfully".format(name=name))
break
else:
print("user {name} login failed".format(name=name))
print("====end====")
while + else
案例,使用while + else方式,实现限制用户输入三次错误密码退出登录
username = 'acai'
password = '123'
count = 0
result = True
while count < 3:
username1 = input("请输入用户名称:")
password1 = input("请输入用户密码:")
if username1 == username and password1 == password:
print("用户{username}登录成功".format(username=username1))
break
else:
print("错误:用户{username}登录失败".format(username=username1))
count += 1
else:
print("登录失败次数超过三次,限制登录")
while + continue
while + continue循环:结束本次循环,直接进入下次循环;continue后面同级代码不会被执行
案例:实现打印1~5,不打印4
count = 0
while count <=5:
if count == 4:
count += 1
continue
print(count)
count += 1
for循环
为什么要有for循环?
for循环在循环取值(遍历取值)比while循环更简洁
可迭代对象
可迭代对象:可以是列表、字典、字符串、元组、集合等
for循环语法
for 变量名 in 可迭代对象:
代码1
案例:列表循环取值
for i in [1,2,3,4]:
print(i)
案例:字典循环取值,字典取值默认取key,如果要取value。如下:
dic = {'k1':1,'k2':2,'k3':3}
for i in dic:
print(i,dic[i])
for循环与while循环的区别
相同之处:都是循环,for循环可以实现的功能,while循环都可以
不同之处:while循环称之为条件循环,循环次数取决于条件何时为假;for循环称之为遍历循环,循环次数取决于遍历对象值的个数
for + range循环
语法:range返回列表数据类型
range(x): 取0~x的值
range(x,y): 取x~y的值
range(x,y,z):取x~y的值,步长为z
案例:打印1~100之间的数字
for i in range(1,101,1):
print(i)
for + range + break +else
示例:通过for循环实现用户登录,用户登录错误超过3次退出登录
for i in range(3):
username = 'acai'
password = '123'
user = input("请输入用户名:")
pawd = input("请输入密码:")
if user == username and pawd == password:
print("用户 {username}登录成功".format(username=user))
break
else:
print("用户 {username}登录失败".format(username=user))
else:
print("用户 {username}输入错误用户名或密码超过3次,限制登录".format(username=user))
for + continue
continue:跳过,不执行代码。
案例:打印0~5,不打印4
for i in range(5):
if i == 4:
continue
print(i)
for嵌套循环:外层循环循环一次,内层循环需要完整的循环一次
示例:
for i in range(3):
print("外层循环--->: ",i)
for j in range(4):
print("内层循环---->: ",j)
案例:99乘法表
for i in range(1,10):
for j in range(1, i+1):
print("{i} x {j} = {result}".format(i=i,j=j,result=i*j), end=" ")
print()
python文件处理
什么是文件?
文件时操作系统提供给用户/用用程序用来操作数据的概念
为什么要用文件?
用户、应用程序通过文件将数据保存在硬盘中,即操作文件就是操作硬盘中的数据
怎么用python操作文件?
python提供open()函数来操作文件读写操作,操作文件有两种模块:
- 文本模式,也叫
t模式 - 二进制/bytes模式,也叫
b模式
什么是文本模式?
读写都是以str(unicode)为单位,必需指定encoding,操作对象比如是文本文件;f.read()读出的结果需要解码成unicode
什么是二进制/bytes模式?
读写都是以bytes为单位,可以针对所有文件。不能指定字符串编码,例如:
with open('test.txt', mode='rb') as f:
res = f.read()
print(res) #使用b模式操作文本,需要用decode方法对数据进行解码;默认二进制数据类型
print(res.decode('utf-8'))
bytes转二进制?
bytes类型:b'必需是纯英文字符串'
print('阿才'.encode('utf-8'))
或
print(bytes('阿才'.encode('utf-8')))
操作文件的模式?
操作文件的模式默认为t模式,如果不指定默认为文本模式
+模式,不能单独使用,必需配合r、w、a
| 模式 | 描述 |
|---|---|
| r+ | 可读可写,如果文件不存在返回;文件不存在返回异常 |
| w+ | 可读可写,如果文件不存在创建空文件;如果文件存在清空文件,然后写数据 |
| a+ | 追加写,如果文件不存在创建空文件;如果文件存在在文件末尾写入数据 |
r、w、a模式需要配合t、b模式配合使用
| 模式 | 描述 |
|---|---|
| rb | bytes读 |
| wb | bytes写 |
| ab | bytes追加 |
r、w、a三种模式应用场景?
r模式:只读模式,当文件不存在时返回文件不存在异常;当文件存在时,文件指针在文件最开始位置
例如:第一次读的时候文件指针在文件开头位置,当第二次读的时候文件指针在文件末尾所以读不出来
with open('test.txt', mode='rt', encoding='utf-8') as f:
print("第一次读:".center(50,"="))
print(f.read())
print("第二次读:".center(50,"="))
print(f.read())
w模式:只写模式,当文件不存在时会创建空文件;当文件存在时会清空文件,文件指针位于首行行首位置;当写入数据完成时,文件指针在写入数据之后
with open('test.txt', mode='wt', encoding='utf-8') as f:
f.write('阿才牛逼')
a模式:追加写,当文件不存在时会创建空文件;当文件存在时,文件指针在文件末尾
with open('test.txt', mode='at', encoding='utf-8') as f:
f.write('牛逼Plus')
x模式:只写模式,如果文件存在返回错误,文件不存在则创建
open()函数对文件操作流程?
打开文件:
f1 = open('test.txt') #f1的值是一种变量,占用的是应用程序的内存空间
print(f1)
操作文件: 读/写文件,应用程序对文件的读写请求都是在向操作系统发送系统调用,然后由操作系统控制硬盘读入内存或者写入硬盘 读文件:
f1 = open('test.txt')
f1.read()
写文件:
f1 = open('test.txt')
f1.write()
保存关闭文件:
f1 = open('test.txt', mode='w')
f1.close()
with open() as用法?
打开文件别名:
with open('test.txt', mode='rt') as f1:
print(f1.read())
打开多个文件:
with open('test.txt', mode='rt') as f1, open('test2.txt', mode='rt') as f2:
print(f1.read())
print(f2.read())
案例:实现文件复制功能
src = input("请输入复制源文件:")
dest = input("请输入复制目标文件:")
with open('{}'.format(src), mode='rt', encoding='utf-8') as f_src, open('{}'.format(dest), mode='w', encoding='utf-8') as f_dest:
for line in f_src.read():
f_dest.write(line)
open()内置方法?
| 方法 | 描述 |
|---|---|
| read() | 读取所有内容 |
| readline() | 每次读一行 |
| readlines() | 以当前位置为起点,把所有数据读出来。 |
| write() | 写入数据 |
| writelines() | 写入多行数据 |
| flush() | 立刻将内存数据写入到硬盘 |
| readable() | 判断文件是否可读 |
| writable() | 判断文件是否可写 |
| name() | 返回文件名 |
文件指针操作?
指针移动:
b模式下移动单位都是以bytes/字节为单位;t模式下十一字符串个数为单位欸
seek(n,模式):
n代表移动文件指针位置,模式分为以下三种情况:
模式:
0参考物是文件开头位置,t模式是字符位置,b模式是字节位置
1参考物是当前指针所在位置,
2参考物是文件末尾
tell()返回当前指针位置
案例:文件修改的两种方式?
方式一:先读取文件数据到内存中,将内存数据修改之后保存到硬盘文件
with open('test.txt', mode='rt', encoding='utf-8') as f:
res = f.read()
print(res)
data = res.replace('牛逼Plus', '阿才牛逼Plus')
with open('test.txt', mode='wt', encoding='utf-8') as f:
f.write(data)
方式二:将文件的数据通过for循环读取每一行,然后将数据替换后写入到临时文件减重;数据修改完成之后删除原文件,将临时文件重命名为原文件
import os
with open('test.txt', mode='rt', encoding='utf-8') as f1,\
open('.test.txt.swap', mode='wt', encoding='utf-8') as f2:
for line in f1:
f2.write(line.replace('牛逼Plus', '阿才牛逼Plus'))
os.remove('test.txt')
os.rename('.test.txt.swap','test.txt')
正则表达式
正则表达式匹配符
| 匹配符 | 描述 |
|---|---|
| ^ | 匹配字符串的开头 |
| $ | 匹配字符串的末尾 |
| . | 匹配任意字符 |
| [...] | 分组匹配字符串,例如:[abc]匹配a,b,c |
| [^...] | 匹配不在[]中的字符串,例如:[^abc]匹配除了a、b、c之外的字符串 |
| * | 匹配0个或多个正则表达式 |
| + | 匹配1个或多个正则表达式 |
| {n} | 精确匹配前面n个表达式匹配的字符串,例如:o{n},匹配两个o |
| {n,} | 匹配前面n个表达式匹配的字符串 |
| {n,m} | 匹配n到m次由前面的正则表达式匹配的字符串 |
| \w | 匹配字母数字及下划线 |
| \w+ | 匹配只至少一个字母 |
| \W | 匹配非字母数字下划线 |
| \s | 匹配任意空白字符串 |
| \S | 匹配任意非空字符串 |
| \d | 匹配任意数字 |
| \d+ | 匹配至少一个数字 |
| \D | 匹配任意非数字 |
| \A | 匹配字符串开始 |
| \Z | 匹配字符串结束,如果存在换行则匹配至换行符前面的字符串 |
| \z | 匹配字符串结束 |
正则表达式re模块方法:
| 方法 | 描述 |
|---|---|
| findall() | 匹配所有字符串中符合规则的项,并返回列表数据类型 |
| search() | 搜索匹配的字符串并返回一个对象,如果不能匹配返回None |
| group() | 从带匹配字符串中取出第一个符合条件的项 |
| match() | 从头开始匹配 |
| finditer() | 功能和findall一样,但是并findall效率更高。返回迭代器,迭代出来的项都是一个对象 |
| compile() | 用于多次匹配,配合match、search方法使用 |
| split() | 根据正则表达式将数据分割为列表元素 |
| sub() | 根据正则表达式替换字符串 |
| subn() | 根据正则表达式替换字符串并且返回替换字符串,返回数据类型为元组 |
正则表达式分组
正则表达式分组,就是把字符串根据正则表达式分为多个组。正则表达式分组使用()来实现,例如:
将h1标签<h1>www.acai.cloud</h1>使用分组的方式分为<h1>、www.acai.cloud、<\h1>三个部分
import re
s1 = '<h1>www.acai.cloud</h1>'
res = re.search('(<\w+>)(.*?)(</\w+>)',s1)
print(res.group(1))
print(res.group(2))
print(res.group(3))
正则表达式分组引用
什么是分组引用,定义一个分组之后其他地方可以引用。例如:表示<h1>和</h1>同时匹配
import re
s1 = '<h1>www.acai.cloud</h1>'
res = re.search('<(?P<tag>\w+)>.*?</(?P=tag)>',s1)
print res.group()
Python函数
函数基础
什么是函数?
函数相当于具备某一功能的代码块,函数的使用必须遵循一个原则:先定义,后调用
定义函数的语法?
def 函数名(参数1,参数2,....):
函数体
return 返回值
示例:
def test():
n = 1
return n
函数调用?
语法:
函数名()
or
函数名(参数1,参数2,.....)
示例:
test()
定义函数原理?
- 申请内存空间保存函数体代码
- 将上述内存地址绑定函数名
- 定义函数不会执行函数体代码,但是会检查函数体语法
调用函数原理?
- 调用函数名找到函数的内存地址
- 调用函数就是触发函数体代码执行
使用函数的意义?
定义函数的三种形式?
无参函数:
def func():
print("哈哈")
有参函数:
def Add(x,y):
return x + y
空函数:函数体代码为pass,函数什么也不执行。通常用来构建程序功能
def test():
pass
函数三种形式的应用场景?
无参函数:调用函数不需要指定参数时。
有参函数:调用函数需要指定参数时。
空函数:构建程序时使用,相当于设计程序功能。
调用函数的三种形式?
语句形式:只调用函数
def test():
return aaa
test()
表达式形式:赋值表达式或数学表达式的方式调用函数
def Add(x,y):
return x + y
print(Add(1,2) * 10)
函数调用当作参数:把调用函数自己当作参数被函数体调用
def Add(x,y):
return x + y
print(Add(Add(1,2),10)) #Add(1,2)先被函数调用计算,计算得到的返回值再被函数调用
函数返回值?
return:时函数结束的表示,即函数体代码运行到return会立刻终止函数的运行。并且会将return后的值当做本次运行的结果返回。
函数返回值的三种形式?
函数返回值None:return
函数返回一个值:return 值
函数返回多个值:return 值1,值2,值3 #用逗号分割开多个值,会被return返回成元组
函数的参数
形参与实参介绍?
形参:在定义函数阶段定义的参数称为形式参数,简称形参
实参:在调用函数阶段传入的参数称之为实际参数,简称实参
示例:
def Add(x,y):
return x * y
Add(5,5)
形参:x,y;相当于变量名
实参:5,5;相当于变量值
实参传入值的三种形式?
形式一:
func(1,2)
形式二:
a=1
b=2
func(a,b)
形式三:
func(int('1'),2)
形参与实参的关系?
在调用阶段,实参会传递值给形参
形参与实参使用?
位置参数:
在函数定义阶段按照从左到右的顺序,依次定义的参数称之为位置参数。
形参特点:每个形参必须被传值
实参特点:按照从左到右的顺序依次传值,实参和形参位置一一对应
示例:
def func(x,y,z):
return x,y,z
print(func(1,2,3))
示例:实参带*,可以将列表元素拆分作为位置实参然后传递给形参,结果返回元组类型数据
def func(x,y,z):
return x,y,z
print(func(*[1,2,3]))
关键字参数?
在函数调用阶段,按照key=value的形式传值,称之为关键字参数
实参特点:可以给指定形参传值
示例:
def func(x,y,z):
return x,y,z
print(func(x=1,y=2,z=10))
位置参数和关键字参数混合使用?
位置实参必须放在关键字前面,不能为同一个形参重复传值
例如:
def func(x,y,z):
return x,y,z
print(func(1,2,z=10))
默认参数?
在定义函数阶段,就已经被赋值的形参,称之为默认参数。
默认参数特点:
在调用函数阶段可以不用给默认形参传值,例如:
def func(x,y,z=20):
return x,y,z
print(func(x=10,y=20))
#如果在调用函数时给默认参数传值,则默认参数的值为新值
print(func(x=10,y=20,z=30))
位置参数和默认参数混合使用?
- 位置形参必需在默认形参的左边
- 默认参数的形参实在函数定义阶段被赋值的,准确来说被赋予的是值的内存地址
- 虽然默认参数可以被指定为任意数据类型,但是不推荐使用可变数据类型
实例:形参默认值不推荐使用可变数据类型,可以定义为None;然后通过判断传入值为None时,设置形参为可变数据类型。
def func(x,y,z,l=None):
if not l: #相当于 if l == None:
l = []
for i in x,y,z:
l.append(i)
return l
print(func(1,2,3))
可变长度的参数?
可变长度参数:在调用函数阶段,实参传入的值的个数不固定;比如:*args、**kargs
可变长度的位置参数?
- 用来接收溢出的位置实参
- 溢出的位置参数
*参数名传入的值返回元组数据类型 - 语法约定可变长度位置参数用
*args表示
示例:
def func(x,y,*args):
return x,y,args
print(func(1,2,3,4,5,6))
可变长度的关键字参数?
- 用来接收溢出的关键字实参
- 形参名会将溢出的关键字实参保存成字典格式返回
- 语法约定可变长度的关键字参数用
**kargs表示
实例:
def func(x,y,**kwargs):
return x,y,kwargs
print(func(x=1,y=2,b=10,c=30))
*args和**kargs组合使用?
*args必需在**kargs之前
例如:
def func(*args,**kwargs):
return args,kwargs
print(func(1,2,aa=10,bb=20))
命名关键字参数?
在定义函数阶段,*后面定义的参数称之为命名关键字参数,例如:
def func(x,y,*,a,b): #a,b称之为命名关键字参数
return x,y,a,b
print(func(1,2,a=3,b=4))
命名关键字参数特点:
命名关键字实参必需按照key=value的形式为其传值
函数的嵌套
什么时函数嵌套?
在函数体内定义其他函数
函数嵌套的调用?
在调用一个函数的郭恒忠又调用其他函数
函数对象?
可以把函数当成变量使用,例如:
def func():
print("acai.cloud")
func1 = func
func1()
可以把函数的参数传给另一个函数,例如:
def func1():
x = 111
def func2(x):
print(x)
func2(func1)
可以把函数当作另一个函数的返回值,例如:
def func1():
print("acai.cloud")
def func2(func1):
return x
res = func2(func1)
res()
可以当做容器类型的一个元素,例如:
def func1():
print("acai.cloud")
l = [func1]
l[0]()
使用函数对象优化atm程序例如:
login_state = None
def Login():
'''
用户登陆
:return:
'''
username = 'acai'
password = '123'
user = input("输入用户:").strip()
pawd = input("输入密码:").strip()
if user == username and pawd == password:
print("用户{}登陆成功".format(user))
global login_state
login_state = True
else:
print("用户或密码错误")
def Transfer_accounts():
'''
用户转账
:return:
'''
if not login_state:
print("用户还未登陆,请登陆后操作")
Login()
else:
print("用户转账成功")
def Withdraw():
'''
用户提现
:return:
'''
if not login_state:
print("用户还未登陆,请登陆后操作")
Login()
else:
print("用户提现成功")
def Check_balance():
'''
用户查询余额
:return:
'''
if not login_state:
print("用户还未登陆,请登陆后操作")
Login()
else:
print("余额还有一个亿")
chioce = {
'1':Transfer_accounts,
'2':Withdraw,
'3':Check_balance
}
while True:
print("""
1 用户转账
2 用户提现
3 查询余额
""")
chioce_options = input("输入操作选项:")
if not chioce_options.isdigit():continue #判断输入是否为数字
if chioce_options in chioce:
chioce[chioce_options]()
else:
print("你输入的指令{}不存在".format(chioce_options))
print部分使用函数对象功能优化atm程序
login_state = None
def Login():
'''
用户登陆
:return:
'''
username = 'acai'
password = '123'
user = input("输入用户:").strip()
pawd = input("输入密码:").strip()
if user == username and pawd == password:
print("用户{}登陆成功".format(user))
global login_state
login_state = True
else:
print("用户或密码错误")
def Transfer_accounts():
'''
用户转账
:return:
'''
if not login_state:
print("用户还未登陆,请登陆后操作")
Login()
else:
print("用户转账成功")
def Withdraw():
'''
用户提现
:return:
'''
if not login_state:
print("用户还未登陆,请登陆后操作")
Login()
else:
print("用户提现成功")
def Check_balance():
'''
用户查询余额
:return:
'''
if not login_state:
print("用户还未登陆,请登陆后操作")
Login()
else:
print("余额还有一个亿")
while True:
info = {
'0':('退出',None),
'1':('转账',Transfer_accounts),
'2':('提现',Withdraw),
'3':('查询余额',Check_balance)
}
for key in info():
print(key[0],info[key][0])
chioce_options = input("输入操作选项:")
if not chioce_options.isdigit():continue #判断输入是否为数字
if chioce_options == '0':
break
if chioce_options in info:
info[chioce_options][1]()
else:
print("你输入的指令{}不存在".format(chioce_options))
名称空间与作用域
名称空间?
名称空间:存放变量名,是对栈区的划分;简单来说,名称空间就是存储变量名与变量内存地址对应关系的一张表。
名称空间的分类?
内置名称空间:python内置的函数,比如abs()
全局名称空间:顶级代码定义的变量,调用的时候才会产生全局名称空间
局部名称空间:函数体内定义的变量
名称空间的加载顺序?
内置名称空间、全局名称空间、局部名称空间
作用域?
变量的作用范围就叫做作用域
global与nonlocal?
在函数体内使用global关键字声明的变量称之为全局变量,例如:
def func1():
x = 11
def func2():
global x
x = 22
func2()
print("func1内x:",x)
func1()
修改函数外层函数包含的变量使用nonlocal关键字
def func1():
x = 11
def func2():
nonlocal x
x = 22
func2()
print("func1内x:",x)
func1()
闭包函数
什么是闭包函数?
闭:指的是该函数时内嵌函数
包:指的是该函数包含对外层函数作用域变量的引用(不是对全局作用域)
一句话概括:内层函数引用了外层函数,叫做闭包函数
定义闭包函数?
闭包函数:函数作用域,例如:
def func1():
x = 'acai.cloud'
def func2():
print(x)
func2()
func1()
闭包函数:函数对象,例如:
def func1():
x = 'acai.cloud'
def func2():
print(x)
return func2
func = func1()
func()
闭包函数传参?
函数的参数使用外层函数的形参传递,例如:
def func1(x):
def func2():
print(x)
return func2
res = func1('acai.cloud')
res()
函数装饰器
什么是装饰器?
在不修改被装饰器对象源代码以及调用方式的情况下为装饰对象添加新功能。
如何定义装饰器?
没有装饰器实现:定义一个index函数,为index函数添加代码运行时间的功能,例如:
import time
def index(name):
time.sleep(1)
print("welcome to {name} index page".format(name=name))
def UseTime(func):
def wrapper(*args,**kwargs):
start_time = time.time()
res = func(*args,**kwargs)
end_time = time.time()
print(end_time - start_time)
return res
return wrapper
res1 = UseTime(index)
res1('www.acai.cloud')
使用装饰器实现:在不修改源代码及调用方式的前提下,实现为index函数添加代码运行时间的功能,例如:
import time
def UseTime(func):
def wrapper(*args,**kwargs):
start_time = time.time()
res = func(*args,**kwargs)
end_time = time.time()
print(end_time - start_time)
return res
return wrapper
@UseTime #相当于index = UseTime(index),然后把index('www.acai.cloud')传值传递给UseTime(index)
def index(name):
time.sleep(1)
print("welcome to {name} index page".format(name=name))
index('www.acai.cloud')
无参装饰器模板?
def Timmer(func):
def wrapper(*args,**kwargs):
# 1. 调用原函数
res = func(*args,**kwargs)
# 2. 为其增加新功能
# 代码块
return res
return wrapper #此处返回wrapper是为了将内存地址返回给Timmer装饰器让被修饰函数饮用。
如何定义有参装饰器?
使用有参装饰器实现统计程序运行时间,例如:
import time
def Timmer(func):
def wrapper(*args,**kwargs):
start_time = time.time()
res = func(*args,**kwargs)
end_time = time.time()
print(end_time - start_time)
return res
return wrapper
@Timmer #相当于info = Timmer(info)
def info(x,y):
time.sleep(1)
print("欢迎来到{name}的博客: {url}".format(name=x,url=y))
info(x='阿才',y='www.acai.cloud')
案例:实现基于多种认证类型的装饰器
def Auth_type(type):
def Auther(func):
def wrapper(*args,**kwargs):
user = input('输入用户:')
pasw = input('输入密码:')
if user == 'acai' and pasw == '123':
print('登陆成功')
if type == 'file':
print('基于file验证')
elif type == 'mysql':
print('基于mysql验证')
elif type == 'ldap':
print('基于ldap验证')
else:
print('未知验证方法')
res=func(*args,**kwargs)
return res
else:
print('用户或密码校验失败')
return wrapper
return Auther
@Auth_type(type='file')
def info(x,y):
print("欢迎来到{name}的博客:{url}".format(name=x,url=y))
info(x='阿才',y='www.acai.cloud')
有参装饰器模板?
def 有参装饰器(x,y,z):
def outter(func):
def wrapper(*args, **kwargs):
res = func(*args, **kwargs)
return res
return wrapper
return outter
@有参装饰器(1,y=2,z=3)
def 被装饰对象():
pass
装饰器的属性?
当函数被装饰器装饰后,被装饰函数返回的属性为装饰器函数的属性,所以需要使用wraps将装饰器属性装饰给原函数,例如:
import time
from functools import wraps
def Timmer(func):
@wraps(func) #获取原函数属性赋值给wrapper
def wrapper(*args,**kwargs):
start_time = time.time()
res = func(*args,**kwargs)
end_time = time.time()
print(end_time - start_time)
return res
return wrapper
@Timmer #相当于info = Timmer(info)
def info(x,y):
time.sleep(1)
print("欢迎来到{name}的博客: {url}".format(name=x,url=y))
info(x='阿才',y='www.acai.cloud')
print(info.__name__)
print(info.__doc__)
多个装饰器代码运行顺序?
当一个函数被装饰器装饰存在多个时,装饰器加载顺序为从下往上,运行顺序从上往下
函数迭代器
什么是迭代器?
迭代器指的是迭代取值的工具。
迭代时一个重复的过程,每次重复基于上一次的结果而继续的,单纯的重复并不是迭代。
比如:有十个数字,第一次取值1,第二次取值2,……,直到取值结束
为什么要有迭代器?
迭代器时用来迭代取值的工具,而涉及到把多个值循环取出来的数据类型有:列表、字符串、元组、字典、集合等。
可迭代对象?
可迭代对象:凡是有__iter__内置方法的数据类型都称之为可迭代对象
可迭代器对象:内置有__next__方法且内置有__iter__方法的对象
可迭代对象.__iter__():得到迭代器对象
迭代器对象.__next__():得到迭代器的下一个值
迭代器对象.__iter__():得到迭代器的本身
调用可迭代对象的__iter__内置方法返回迭代器对象,例如:通过迭代器对象取值
str = 'acai'
str_iter = str.__iter__()
while True:
try:
print(str_iter.__next__())
except StopIteration:
break
for循环工作原理?
for循环,循环的值必须是一个可迭代对象或迭代器,因为迭代器调用iter()方法会返回迭代器对象,例如:
dict1 = {'a':1,'b':2,'c':3}
for k in dict1:
print(k)
dict1.__iter__()得到一个迭代器对象
迭代器对象__next__()拿到一个返回值,然后将该返回值赋值给k
循环步骤2,知道抛出StopIteration,停止循环
函数生成器
什么是生成器?
在函数体中存在yield关键字,调用函数并不会执行函数体代码;会返回一个生成器对象,生成器即迭代器。
一句话概括:生成器就是自定义的迭代器。
定义生成器?
def func():
print('第一次')
yield 1
print('第二次')
yield 2
print('第三次')
yield 3
res = func()
res.__next__() #此处__next__()方法可以简写成next(res)
res.__next__()
res.__next__()
从上面的代码示例可以看出,每调用一次__next__()方法遇到yield关键字,会把结果返回给yield
例如:使用生成器,实现range()函数功能
def my_range(start,stop,step):
while start < stop:
yield start
start += step
res = my_range(1,10,1)
print(next(res))
yield表达式?
- x=yield 返回值,例如:
def dog(name):
print('{name}的博客'.format(name=name))
while True:
x = yield
print('{name}的博客{url}'.format(name=name,url=x))
g = dog('阿才')
# g.send()方法相当于把值赋值给yield,然后由yield赋值给x
g.send(None)
g.send('www.acai.cloud')
函数的递归
什么是函数递归?
函数递归的本质就是函数循环。
函数递归的调用?
函数递归的调用是函数嵌套调用的一种形式,在调用一个函数的过程中又直接或间接地调用本身。
例如:
def func():
print('func')
func()
func()
为什么要使用函数递归?
函数递归可以实现重复运行代码,递归调用不应该无限地调用下去,应该使用return在某个条件下接入,例如:
def func(x):
if x >= 900:
return
print(x)
x += 1
func(x)
func(1)
函数递归的两个阶段?
回溯:一层一层地调用下去
递推:满足某种结束条件,结束递归调用,然后一层一层返回
函数递归调用应用?
案例:获取列表中的元素
适用于嵌套列表
l = [1,2,[3,4]]
def func(list1):
for x in list1:
if type(x) is list:
func(x)
else:
print(x)
func(l)
生成式
列表生成式?
例如:
l = ['aaa','abb','acc']
new_l = []
for name in l:
if name.startswith('a'):
new_l.append(name)
print(new_l)
生成式简写:
l = ['aaa','abb','acc']
new_l = [name for name in l if name.startswith('a')]
print(new_l)
三元表达式
什么是三元表达式?
判断条件,条件成立返回1,条件不成立返回2;相当于一行代码实现功能
三元表达式语法?
条件成立时要返回的值 if 条件 else 条件不成立时要返回的值
例如:
def func(a,b):
if a > b:
print(a)
else:
print(b)
三元表达式简写:
def func(a,b):
res = a if a > b else b
print(res)
python包
什么是python包?
包含有__init__.py文件的文件夹
为什么要有python包?
包的本质是模块的一种形式,包是用来被当作模块导入使用。
包的使用?
绝对路径导入:
from 包.模块 import 方法
对于执行python文件来说导入包的路径和父目录同级,比如:
├── bin
│ ├── __init__.py
│ └── main.py
├── conf
│ ├── __init__.py
│ └── local_settings.py
├── core
│ ├── atm.py
│ └── __pycache__
│ └── atm.cpython-37.pyc
├── __init__.py
└── lib
├── common.py
├── logger.py
bin/main.py 导入lib/common模块正确姿势应该是:
from lib.common import Runner
相对路径导入:
from .包.模块 import 方法
或
from ..包.模块 import 方法
相对路径导入包的局限性:
仅限于包内使用,不能跨包。推荐使用绝对路径导入包
软件目录开发规范
| 顶级目录 | 项目名称 |
|---|---|
| bin | 执行文件,入口代码 |
| conf | 配置文件 |
| db | 数据库配置 |
| lib | 自定义模块路径 |
| core | 核心代码逻辑 |
| logs | 日志文件 |
| setup.py | 安装、部署、打包代码脚本 |
| requirements.txt | python依赖包相关 |
示例:ATM取款机
ATM
├── bin
│ ├── __init__.py
│ └── main.py
├── conf
│ ├── __init__.py
│ ├── local_settings.py
│ └── __pycache__
│ ├── __init__.cpython-37.pyc
│ └── local_settings.cpython-37.pyc
├── core
│ ├── atm.py
│ └── __pycache__
│ └── atm.cpython-37.pyc
├── __init__.py
└── lib
├── common.py
└── __pycache__
├── common.cpython-37.pyc
└── logger.cpython-37.pyc
ATM/core/atm.py
def Login():
print("登陆成功")
def Query():
print("余额还有一个亿")
def Transfer_account():
print("转帐成功")
def Info():
while True:
info = {
'0':('退出',exit),
'1':('登录',Login),
'2':("查询",Query),
'3':('转账',Transfer_account)
}
for k in info:
print(k[0],info.get(k)[0])
chioce_ops = input("请输入操作选项:")
if not chioce_ops.isdigit():
print("输入指令不是数字,请重新输入")
continue
if chioce_ops in info:
info[chioce_ops][1]()
else:
print("指令不存在,请重新输入")
ATM/lib/common.py
from core.atm import Info
from core.atm import Login
from core.atm import Query
from core.atm import Transfer_account
def Runner():
Info()
ATM/conf/local_settings.py
import os
#获取ATM项目目录
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
ATM/bin/main.py
from lib.common import Runner
if __name__ == '__main__':
#运行Runner函数
Runner()
运行结果,如下:
0 退出
1 登录
2 查询
3 转账
请输入操作选项:
python模块
模块基础
什么是模块?
模块可以理解为代码的集合体,当我们要使用的时候通过调用模块实现代码功能。而不用每次使用代码功能的时候都要写一遍,使用模块可以大量节约开发成本和时间。
模块可分为三大类:
- 内置模块
- 第三方模块
- 自定义模块
模块的四种形式:
- 使用python编写的
.py文件 - 已被编译为共享库或DLL的C或C++扩展
- 把一系列模块组织到一起的文件夹,文件夹下有一个
__init__.py被称为python包 - 使用C编写并链接到python解释器的内置模块
为何调用模块?
导入模块python做了哪些事情?
- 执行foo.py
- 产生foo.py的名称空间,将foo.py运行过程中产生的名字都丢到foo的名称空间
- 再当前文件中产生的有一个名字foo,该名字指向步骤2中产生的名称空间
- 导入模块不会执行模块代码
导入模块语法?
导入单个模块
import 模块名.方法
或
from 模块 import 方法
导入多个模块
import module1,module2,... #不建议这么些,建议一行导入一个模块
导入模块的规范?
导入模块的顺序:
- python内置模块
- python第三方模块
- python自定义模块
导入模块的语法?
导入模块:
import foo
模块别名:
import foo as f
导入模块一个功能:
from foo import x
自定义模块命名规范?
自定义模块名称应该纯小写加下划线
python文件的两种用途?
- 被当作程序执行
- 被当作模块导入
当foo.py被当作程序运行时:
__name__的值为'__main__'
当foo.py被当作模块导入时:
__name__的值为'foo'
模块循环导入问题?
如果代码逻辑存在模块的循环导入问题:比如A导入B,B导入C,C导入A;为了解决这个问题,可以将导入模块定义到函数内,例如:
def func():
from aaa import bbb
print(y)
模块导入的优先级?
python导入模块的优先级是通过内置模块sys.path环境变量中存放文件顺序依次查找要导入的模块,临时生效;如果要添加自定义模块路径到python环境变量,如下操作:
import sys
sys.path.append("/root/aaa")
sys
使用场景?
通常用来操作系统相关
模块应用场景?
| 方法 | 描述 |
|---|---|
| sys.argv | 接收命令行参数 |
| sys.exit() | 退出程序 |
| sys.version | python版本 |
| sys.modules | python内置模块 |
| sys.path | python环境变量 |
time
使用场景?
通常用来获取或操作系统时间
什么是时间戳?
从1970到现在经过的时间
时间戳的作用?
用于时间间隔的计算。
常见的三种时间格式?
- 时间戳
- 格式化字符串时间
- 结构化的时间
模块应用场景?
打印时间戳
import time
print(time.time())
格式化字符串时间,按照指定格式打印时间
import time
print(time.strftime('%Y-%m-%d %H:%M:%S'))
结构化时间:
import time
res = time.localtime()
获取年
print(res.tm_year)
获取月
print(res.tm_mon)
获取日
print(res.tm_mday)
三种格式时间间的相互转换?
结构化时间 ------> 时间戳
结构化时间转时间戳:
import time;print(time.mktime(time.localtime()))
时间戳转结构化时间:
import time;print(time.localtime(time.time()))
结构化时间 ------> 格式化字符串时间
结构化时间转格式化字符串时间:
import time
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
格式化时间转结构化时间:
import time
print(time.strptime('2020-09-03 11:12:13', '%Y-%m-%d %H:%M:%S'))
时间戳 ------> 格式化字符串时间
套路:时间戳 ------> 结构化时间 ------> 格式化字符串时间
random
使用场景?
用来获取随机数,可实现验证码等操作
应用场景?
| 方法 | 描述 |
|---|---|
| random.random() | 0~1之间小数 |
| random.randint(1,9) | 大于等于1且小于等于9之间的整数 |
| random.randrange(1,3) | 大于等于1且小于3之间的整数 |
| random.choice([1,2,3,4]) | 从列表中选择一个随机 |
| random.sample([1,2,3,4],3) | 列表元素任意3个组合 |
| random.uniform(1,3) | 大于1小于3的小数 |
| random.shuffle([list1]) | 随机打乱顺序,相当于洗牌 |
应用案例?
知识点:
计算机中存储字母的方式是通过ascii码,来把字母转换为数字存储。
数字转ascii字母:
chr(666)
字母转ascii数字:
ord('z')
需求:
- 实现6位验证码
- 验证码包含数字、小写字母、大写字母
实现:
#小写字母97~122
#大写字母65~90
import random
res = []
for i in range(0,2):
res1 = chr(random.randrange(65,90))
res.append(res1)
res2 = chr(random.randrange(97,122))
res.append(res2)
res3 = str(random.randrange(0,9))
res.append(res3)
random.shuffle(res)
print("".join(res))
os
| 方法 | 描述 |
|---|---|
| os.getcwd() | 获取当前目录路径 |
| os.chdir('dirname') | 切换目录 |
| os.curdir | 获取当前目录 |
| os.pardir | 获取父目录 |
| os.makedirs('dirname1/dirname2') | 递归创建目录 |
| os.removedirs('dirname1') | 若目录为空,则删除,并递归到上级目录;非空目录无法删除 |
| os.mkdir('dirname1') | 创建目录 |
| os.listdir('dirname1') | 查看目录下所有子目录 |
| os.remove('dirname') | 删除一个文件 |
| os.rename('oldname','newname') | 重命名文件或目录 |
| os.stat('filename1') | 获取文件或目录信息 |
| os.system('ls') | 运行shell命令 |
| os.environ() | 获取环境变量 |
| os.path.abspath('path') | 获取绝对路径 |
| os.path.split('path') | 将path分割成目录和文件名以元组形式返回 |
| os.path.dirname('path') | 返回 path的目录 |
| os.path.basename('path') | 返回 path最后的文件名 |
| os.path.split('path') | path的第二个元素 |
| os.path.exists() | 如果path存在返回true,否则false |
| os.path.isabs('path') | 如果path是绝对路径返回true |
| os.path.isfile('path') | 如果path是file返回true |
| os.path.isdir('path') | 如果path是dir返回true |
| os.path.join('path1','path2') | 将多个路径组合返回 |
| os.path.getatime('path') | 返回path所只想的文件或目录的最后存储时间 |
| os.path.getmtime('path') | 返回path所指向文件或目录的最后修改时间 |
| os.path.getsize('path') | 返回path大小 |
| os.walk(top[, topdown=True[, onerror=None[, followlinks=False]]]) | 文件、目录遍历器 |
os.walk()方法?
参数:
| 参数 | 描述 |
|---|---|
| top | 要遍历的目录地址,返回一个三元组:root(文件夹路径)、dirs(目录)、files(文件) |
| topdown | 为True,优先遍历top目录;否则优先遍历top的子目录(默认) |
| onerror | 需要一个callable对象,当walk需要异常时,会调用 |
| followlinks | 如果为True,会遍历目录下的快捷方式,如果为False,优先遍历top的子目录 |
shutil
使用场景?
复制文件、解压缩文件等
应用场景?
| 方法 | 描述 |
|---|---|
| shutil.copyfileobj(open('old.txt','r'), open('new.txt','w')) | 以打开文件的方式复制文件 |
| shutil.copyfile('old.txt','new.txt') | 直接复制文件 |
| shutil.copymode('old.txt','new.txt') | 复制文件权限。内容、组、用户均不变 |
| shutil.copystat('old.txt','new.txt') | 仅复制状态信息,包括:mode bits atime、mtime flags |
| shutil.copy('old.txt','new.txt') | 复制文件和权限 |
| shutil.copy2('old.txt','new.txt') | 复制文件和状态信息 |
| shutil.copytree('folder1','folder2') | 递归复制文件夹 |
| shutil.make_archive('aaa.txt','gztar', root_dir='/root') | 创建压缩包 |
json & pickle
什么是序列化?
把不能直接存储在文件中的数据变得可存储,这个过程叫做序列化
什么是反序列化?
把文件中的数据内容拿出来,恢复成原来的数据类型,这个过程叫做反序列化
为什么要用序列化?
用户存储跨平台数据交互(比如:java和python之间交互)
json和pickle的区别?
json、pickle都是用来序列化数据的;pickle可以序列化任意数据类型而json只能序列化特定的数据类型,比如:字符串、字典、列表、元组等
| json | pickle |
|---|---|
| 可以再不通开发语言间交互 | 只能再python程序间交互 |
| 只能序列化python常规数据类型 | 可以序列化任意数据类型 |
| 序列化后的对象可读 | 序列化后的对象为二进制字节流 |
json内置方法?
| 方法 | 描述 |
|---|---|
| dumps | 把对象序列化成字符串 |
| dump | 把对象序列化后写入文件 |
| loads | 把对象反序列化成原来的数据 |
| load | 把对象从文件拿出来,反序列化成原来的数据 |
pickle内置方法?
| 方法 | 描述 |
|---|---|
| dumps | 把任意对象序列化成一个bytes |
| dump | 把对象序列化后写入file,即文件对象 |
| loads | 把任意bytes反序列化成原来的数据 |
| load | 把文件对象中的内容拿出来,反序列化成原来数据 |
json使用场景?
注意:json合适字符串是双引号,不是单引号
序列化:
import json
#序列化
list1 = [1,2,3,4]
res = json.dumps(list1)
print(res,type(res))
反序列化:
#反序列化
res = json.loads(res)
print(res,type(res))
pickle使用场景?
序列化:
import pickle
lst = [1,2,3]
#将lst列表序列化成二进制字节流赋值给res1
res1 = pickle.dumps(lst)
print(res1,type(res1))
反序列化:
#将二进制字节流res1反序列化成,序列化之前的数据类型
res2 = pickle.loads(res1)
print(res2,type(res2))
configparser
内置方法?
创建一个config对象:
import configparser
confg = configparser.ConfigParser()
| 方法 | 描述 |
|---|---|
| confg.read('test.conf') | 读配置文件 |
| confg.sections() | 获取sections |
| confg.options('default') | 获取某一section下所有options |
| confg.items('BeiJing') | 获取items |
| confg.get('GuangZhou','name') | 获取指定配置项的值,字符串类型 |
| confg.getint('BeiJing','age') | 获取指定配置项的值,整数类型 |
| confg.getboolean('default','enable_cinder') | 获取指定配置项的值,数据类型布尔值 |
hashlib
什么是hash?
hash是一种算法,该算法接受输入的内容,经过运算得到一串hash值;一般用来计算文件是否被修改
hash值的特点?
- 只要传入的内容一样,得到的hash值一样
- 不能由hash值反解内容
hash的用途?
- 用于密文传输与验证
- 文件完整性验证
hash的使用场景?
import hashlib
m = hashlib.md5()
m.update('hello'.encode('utf-8'))
res = m.hexdigest()
print(res)
suprocess
用来执行操作系统命令的模块
import subprocess
obj = subprocess.Popen('ls /home', shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
输出正确内容:
res = obj.stdout.read()
print(res)
print(res.decode('utf-8'))
输出错误内容:
err_res = obj.stderr.read()
print(err_res)
Logging
处理excel
python处理excel的模块?
xlrd:读取excel文件数据
xlsxwriter/xlwd:写excel文件
xlrd模块语法?
模块方法:
| 方法 | 描述 |
|---|---|
| open_workbook() | 打开excel文件 |
| sheets() | 获取工作表 |
| sheet_by_name() | 获取工作表名称 |
| sheet_by_index() | 获取工作表索引 |
| sheet_by_name("工作表").nrows | 获取工作表行 |
| sheet_by_name("工作表").ncols | 获取工作表列 |
| sheet_by_name("工作表").row_values() | 获取工作表行内容 |
| sheet_by_name("工作表").col_values() | 获取工作表列内容 |
代码示例:
#打开excel文件
xl=xlrd.open_workbook(r"userinfo.xls")
#通过索引获取工作表
table = xl.sheets()[0]
#通过工作表名称获得工作表
table=xl.sheet_by_name(“Sheet1”)
#通过工作表索引获得工作表
table=xl.sheet_by_index(0)
#获取工作表的行数
rows = table.nrows
#获取工作表的列数
cols = table.ncols
#获取工作表的行内容
row_values = table.row_values(0) # 获取第一行的内容,得到的是一个列表
#获取工作表的列内容
col_values = table.col_values(0) # 获取第一列整列内容,得到的是一个列表
xlswriter模块语法?
xlswriter模块方法:
| 方法 | 描述 |
|---|---|
| Workbook(‘file.xls’) | 创建excel |
| add_worksheet('工作表') | 创建工作表 |
| write_string(0,0,'uname') | 写入数据 |
| set_column('A:B',30) | 调整列宽 |
代码示例:
#生成excel文件
xl = xlsxwriter.Workbook(r'C:\\DATA\\test.xls')
#生成工作表
table = xl.add_worksheet('sheet1')
#写入数据
table.write_string(0,0,'uname')
table.write_string(0,1,'pwd')
#调整列宽
table.set_column('A:B',30)
#带样式写入
style = xl.add_format({'bg_color': 'red'}) # 添加背景色红色
table.write_string(row,col,val,style)
python面向对象
面向对象基础
面向过程与面向对象编程?
面向对象:将程序看作一堆对象的集合,实现功能的方式就是通过对象之间的交互来实现。
面向过程:将需要解决的问题按步骤划分,一步一步完成每一个步骤;并且步骤之间有联系。
面向对象与面向过程编程优缺点?
| 名称 | 优点 | 缺点 |
|---|---|---|
| 面向过程 | 复杂问题可以分步骤完成 | 扩展性、维护性差;如果中间某一环节有问题整体都会发生问题 |
| 面向对象 | 扩展性高;且互不影响 | 当程序不需要扩展性时就会变得很复杂 |
对象与类?
对象:对象是具备某些功能的实体,比如:人、鸟、花、草等
类:类是一个抽象的概念。
类的定义?
定义类共有三种形式:
形式一:
class Car:
pass
形式二:
class Car():
pass
形式三:
class Car(object):
pass
类的实例化?
类的实例化相当于把类实例化成obj对象,通过obj对象访问类的属性和方法。
class Car:
pass
#相当于把类实例化成obj对象
obj = Car()
类的基本结构?
类的基本结构由成员属性、成员方法组成
成员属性:类的特征,相当于类的变量
成员方法:类的功能,相当于类的函数
例如:color为Car类的属性,func()为Car类的方法
class Car():
color = '黄色'
def func(self):
print('小车会跑')
类的命名规则?
类的名称第一个字符串只能是字母,且字符串为大写字母
类的三大特征?
封装:对类的成员属性、方法进行保护;控制外界对内部成员的访问、修改、删除等操作。
继承:一个类除了自己的属性、方法之外,还能获取其他类的属性。
多态:不通的子类对象,调用相同的父类方法,产生不通的结果。
类的私有属性、方法?
类的私有属性、方法只能再类内调用,使用__指定该属性、方法为私有属性、方法
例如:__logo为类的私有属性;__info()为类的私有方法
class MyCar():
color = '黄色' #公有成员属性
__logo = '五菱宏光' #私有成员属性
def drive(self): #公有成员方法
print("小车可以跑")
def __info(self): #私有成员方法
print("可以泡妹子")
类的实例化?
例如:
class MyCar():
color = '黄色' # 公有成员属性
__logo = '五菱宏光' # 私有成员属性
def drive(self): # 公有成员方法
print("小车可以跑")
def __info(self): # 私有成员方法
print("可以泡妹子")
实例化类:
obj = MyCar()
调用方法:
obj.drive()
调用属性:
print(obj.color)
实例化的对象动态添加公有属性、方法?
动态添加无参方法:
class MyCar():
color = '黄色' # 公有成员属性
__logo = '五菱宏光' # 私有成员属性
def drive(self): # 公有成员方法
print("小车可以跑")
def __info(self): # 私有成员方法
print("可以泡妹子")
#实例化类
obj = MyCar()
def custom1():
print("小车可以泡妹子")
obj.custom1 = custom1()
obj.custom1
动态添加有参方法:
class MyCar():
color = '黄色' # 公有成员属性
__logo = '五菱宏光' # 私有成员属性
def drive(self): # 公有成员方法
print("小车可以跑")
def __info(self): # 私有成员方法
print("可以泡妹子")
#实例化类
obj = MyCar()
def custom2(name):
print(name)
obj.custome2 = custom2("acai.cloud")
obj.custome2
调用类的私有属性、方法?
在类外python是禁止调用类的私有属性和方法的,我们可以通过定义公有类方法、属性;通过调用这个类方法、属性实现;例如:
class Air():
#公有成员属性
captain = 'Acai'
#私有成员属性
__airsiter = 2
#公有绑定方法
def fly1(self):
print("飞机会飞")
#公有无参方法
def fly2():
print("百公里油耗8L")
#绑定私有成员方法
def __plane_info(self):
print("飞机上的空姐数量是: %d" %(self.__airsiter))
#用类调用私有方法
def __plane_info2():
print("飞机上的空姐数量是: %d" %(Air.__airsiter))
#定义pub_info公有方法,调用私有成员属性和方法
def pub_info1():
print(Air.__airsiter)
Air.__plane_info2()
def pub_info2(self):
print(self.__airsiter)
self.__plane_info()
#实例化类为obj对象
obj = Air()
#通过类调用私有属性、方法
Air.pub_info1()
#通过对象调用私有属性、方法
obj.pub_info2()
删除类的属性、方法?
实例化的对象删除公有属性、方法:
class Air():
#公有成员属性
captain = 'Acai'
#私有成员属性
__airsiter = 2
#公有绑定方法
def fly1(self):
print("飞机会飞")
#实例化Air类为obj对象
obj = Air()
#查看captain成员属性
print(obj.captain)
#给obj对象定义一个captain成员属性
obj.captain = 'Acai.cloud'
#查看obj所有属性、方法
print(obj.__dict__)
#删除obj对象captain属性
del obj.captain
#查看删除obj对象captain属性后的所有属性、方法
print(obj.__dict__)
类的属性
python的类提供了内置属性,例如:
| 方法 | 描述 |
|---|---|
__dict__ | 获取对象或类内部的成员结构 |
__doc__ | 获取对象或类的内部文档 |
__name__ | 获取类函数名 |
__class__ | 获取当前对象所属的类 |
__basees__ | 获取一个类直接继承的所有父类,返回元组 |
使用场景?
class Man():
pass
class Woman():
pass
class Children(Man,Woman):
"""
成员属性:eye
成员方法:skylight、moonread、__makebaby
"""
eye = "血轮眼"
def skylight(self):
print("出生使用天照眼")
def moonread(self):
print("出生使出武功绝学")
def __makebaby(self):
print("私有方法")
obj = Children()
#获取成员属性、方法
print(Children.__dict__)
#获取类的文档
print(Children.__doc__)
#获取类函数名
print(Children.__name__)
#获取对象所属类
print(obj.__class__)
#获取类继承所有父类
print(Children.__bases__)
类的方法
类的方法可分为以下三种:
- 普通方法:可以有参数或者无参数,当成正常函数的调用
- 绑定方法:绑定到对象,绑定到类
- 静态方法:无论是对象还是类,都可以调用
普通方法?
普通方法就是使用类调用方法,但是调用方法时不会传递默认的self参数。例如:
class Dog():
name = "旺财"
#普通方法
def jiao():
print("小狗旺旺地叫")
Dog.jiao()
对象绑定方法?
绑定方法对象,用对象调用方法;例如:
class Dog():
name = "旺财"
def eat(self):
print("小狗喜欢吃骨头")
obj.eat()
类绑定方法?
使用classmethod
class Dog():
name = "旺财"
@classmethod #系统自带的装饰器
def tail(cls):
print("小狗喜欢摇尾巴")
Dog.tail()
静态方法?
无论是对象还是类,都可以调用
class Dog():
name = "旺财"
@staticmethod #系统内置装饰器
def jump():
print("小狗喜欢接飞盘")
obj.jump()
Dog.jump()
类的内置方法
__init__()构造方法
什么是
__init()构造方法?
用来给类实例化对象参数,简单理解就是给类指定调用参数;实例化的参数只能再类内调用且没有返回值。
基本语法:如果定义类定义了构造方法,那么在实例化类时需要指定该类参数
class Air():
def __init__(self,name,age,addr):
self.name = name
self.age = age
self.addr = addr
def base(self):
print("%s %s %s" %(self.name,self.age,self.addr))
obj = Air(name='acai',age=27,addr='BeiJing')
obj.base()
__new__()方法
| 触发时机 | 实例化类生成对象的时候触发,触发时机在__init__()方法之前 |
|---|---|
| 功能 | 自定义类返回的object对象 |
| 参数 | 至少一个cls接收当前的类 |
| 返回值 | 通常返回对象或None |
什么是
__new()__方法?
__new()__方法用来自定义类返回的obj对象。
例如:
返回类对象
class MyClass1(object):
def __new__(cls, *args, **kwargs):
#1. 借助父类object类.方法()
obj = object.__new__(cls)
#2. 返回其他类的对象
return obj
obj = MyClass1()
print(obj)
不返回任何对象:
class MyClass1(object):
def __new__(cls, *args, **kwargs):
return None
obj = MyClass1()
print(obj)
new方法和init方法的区别?
new方法:用来创建对象;参数传递类
init方法:用来初始化对象;参数传递类对象
原因:因为先创建对象,再去初始化对象,所以new方法快于init方法
例如:
class A():
def __init__(self):
print(1)
def __new__(cls, *args, **kwargs):
print(2)
return object.__new__(cls)
obj = A()
new方法的参数要和init方法的参数一一对应?
class A():
def __new__(cls, *args, **kwargs):
return object.__new__(cls)
def __init__(self,name,age,addr):
self.name = name
self.age = age
self.addr = addr
print(name,age,addr)
obj = A('aca',27,'bj')
new方法返回其他类对象不会执行init方法;如果new方法返回本类对象才会执行init方法?
例如:new方法返回其他类对象:
class A():
print("A类被触发")
obj1 = A()
class B():
def __new__(cls, *args, **kwargs):
return obj1
def __init__(self):
print("B类构造方法被触发")
obj2 = B()
单态模式?
什么是单态模式:
无论实例化多少次,都有且只有一个对象
使用单态模式的意义:
为了节省内存空间,仅仅是为了调用类中的成员,不需要额外给该类对象添加成员
单态模式基本语法:
class A():
__obj = None
def __new__(cls, *args, **kwargs):
#如果有对象直接返回,如果没有对象就创建
print('查看__obj对象内存地址',cls.__obj)
if cls.__obj is None:
cls.__obj = object.__new__(cls)
return cls.__obj
obj1 = A()
print(obj1)
obj2 = A()
print(obj2)
单态模式和构造方法?
class A():
obj = None
def __new__(cls, *args, **kwargs):
if cls.obj is None:
cls.obj = object.__new__(cls)
return cls.obj
def __init__(self,name):
self.name = name
obj1 = A('acai')
print(obj1.name)
obj2 = A('cloud')
print(obj2.name)
说明: obj1和obj2都是同时指向同一个对象,因为对象只创建了一个对象 .name是获取类参数的值把obj1和obj2对应值替换了
__del__()析构方法
| 触发时机 | 当对象被内存回收的时候自动触发(1. 执行完毕回收所有变量,2. 所有对象被del的时候) |
|---|---|
| 功能 | 对象使用完毕后资源回收 |
| 参数 | 一个self接收对象 |
| 返回值 | 无 |
基本语法?
- 执行完毕回收所有变量时:
class YellowDog():
food = 'eat meat'
def __init__(self,name):
self.name = name
def __del__(self):
print("析构方法被触发")
#1. 执行完毕回收所有变量
obj = YellowDog("dog")
print(obj.name)
- 所有对象呗del的时候:
class YellowDog():
food = 'eat meat'
def __init__(self,name):
self.name = name
def __del__(self):
print("析构方法被触发")
#2. 所有对象被del的时候
#当一个值,没有任何变量指向或者说引用,这个值才会被释放
other_obj = obj
print("-----start-----")
#当需要触发del方法时,需要把obj、other_obj对象都删除
del other_obj
del obj
print("-----end------")
实战案例?
模拟文件操作:打开文件、读取文件、关闭文件
import os
class ReadFile():
def __new__(cls, read_file):
#判断文件是否存在
if os.path.exists(read_file):
#文件存在创建一个对象
return object.__new__(cls)
else:
return print("{} 文件不存在" .format(read_file))
def __init__(self,read_file):
#接收传入的读取的文件
self.read_file = read_file
#打开文件操作
self.f = open(read_file,mode='r',encoding='utf-8')
#使用析构方法,析构放在在程序执行返程之后执行;所以通过析构方法将文件关闭
def __del__(self):
self.f.close()
def readcontent(self):
content = self.f.read()
return content
obj = ReadFile('test.txt')
res = obj.readcontent()
print(res)
__str__()方法
| 触发时机 | 使用print(对象)或者str(对象)的时候触发 |
|---|---|
| 功能 | 查看对象 |
| 参数 | 一个self接收当前对象 |
| 返回值 | 必需返回字符串类型 |
实战案例?
触发方式一:print打印对象触发
class Cat():
gift = "猫有九条命"
def __init__(self,name):
self.name = name
def __str__(self):
return self.name
obj = Cat("tom")
print(obj)
触发方式二:使用str方法方式
class Cat():
gift = "猫有九条命"
def __init__(self,name):
self.name = name
def __str__(self):
return self.info()
def info(self):
return "{} 小猫有故事".format(self.name)
obj = Cat("tom")
res = str(obj)
print(res)
__repr__()方法
| 触发时机 | 使用repr(对象)的时候触发 |
|---|---|
| 功能 | 查看对象,与__str__()方法相似 |
| 参数 | 一个self接收当前对象 |
| 返回值 | 必需返回字符串类型 |
实战案例?
class Mouse():
gift = "打洞"
def __init__(self,name):
self.name = name
def __repr__(self):
return self.mouse_info()
def mouse_info(self):
return "{} 老鼠会{}".format(self.name,self.gift)
obj = Mouse("jack")
#repr强转obj对象时触发
res = repr(obj)
print(res)
__call__()方法
| 触发时机 | 把对象当作函数调用时触发 |
|---|---|
| 功能 | 将对象模拟函数化操作 |
| 参数 | 参数不固定,至少一个self参数 |
| 返回值 | 看需求 |
基本语法?
class MyClass():
def __call__(self, *args, **kwargs):
print("call方法被触发")
obj = MyClass()
obj()
实战案例?
模拟洗衣服的过程:
class Wash():
#默认系统是不能直接让对象用函数的方式调用,所以需要__call__方法调用方法;例如:调用step1、step2、step3
def __call__(self, *args, **kwargs):
self.step1()
self.step2()
self.step3()
def step1(self):
print("脱衣服")
def step2(self):
print("衣服放水里,加洗衣粉")
def step3(self):
print("洗衣服")
obj = Wash()
obj()
模拟init内置方法:
class MyInt():
def __call__(self, num):
#判断call方法传入的num参数是不是一个布尔数据类型
if isinstance(num,bool):
if num == True:
return 1
else:
return 0
elif isinstance(num,int):
return num
#判断如果num是浮点数据类型,通过split取整数部分
elif isinstance(num,float):
res = str(num).split(".")
return res[0]
obj = MyInt()
print(obj(3.3))
__bool__()方法
| 触发时机 | 使用bool(对象)的时候触发 |
|---|---|
| 功能 | 强转对象,将对象强转为布尔类型 |
| 参数 | 一个self接收当前对象 |
| 返回值 | 必须是布尔类型 |
实战案例?
class MyBool():
def __bool__(self):
return True
obj = MyBool()
print(bool(obj))
__add__()方法
| 触发时机 | 使用对象进行运算相加的时候触发 |
|---|---|
| 功能 | 对象相加运算 |
| 参数 | 一个对象参数 |
| 返回值 | 返回运算后的结果 |
实战案例?
class MyAdd():
def __init__(self,num):
self.num = num
def __add__(self, other):
return self.num + other
obj = MyAdd(7)
res = obj + 7
print(res)
类的继承
什么是类的继承?
类获取自己本身的属性和方法还获取了其他类的属性和方法,叫做类的继承。
类继承的基本语法?
如下代码所示,B类继承了A类;也就是说A类是B类的父类
class A():
pass
class B(A):
pass
类继承的分类?
类的继承可以分为子类、父类。
子类:一个类继承其他类,叫做子类也叫衍生类。
父类:被一个类继承的类叫做父类,也叫基类、超类。
类继承的方式?
类继承的方式分为两种:单继承、多继承
单继承:一个子类继承一个父类
多继承:一个子类继承多个父类
单继承?
单继承特性:
子类继承父类之后,子类可以调用父类所有的公有成员属性、方法
class Human():
hair = '金色'
sex = '男'
def djy(self):
print("打酱油")
def work(self):
print("工作")
class Man(Human):
pass
obj = Man()
obj.djy()
obj.work()
print(obj.hair)
print(obj.sex)
子类继承父类之后,子类无法调用父类的私有成员属性、方法
class Human():
def __money(self):
print("挣钱")
class Man(Human):
pass
obj = Man()
子类继承父类之后,子类可以重写父类的同名方法;什么是重写父类方法:子类和父类存在相同的方法但是返回结果不通。
class Human():
def work(self):
print("挣钱")
class Man(Human):
def work(self):
print("学习")
obj = Man()
obj.work()
子类继承父类之后,如果子类和父类都存在相同的属性、方法;优先调用子类属性、方法
多继承?
基本语法:
class Father():
property = 'father'
def F_boby(self):
print('father boby')
class Mather():
property = 'mather'
def M_boby(self):
print('mather boby')
class Daughter(Father,Mather):
pass
obj = Daughter()
print(obj.property)
obj.F_boby()
多继承成员属性、方法优先级:
如果子类存在成员属性、方法先调用自己的成员属性、方法
如果子类不存在成员属性、方法先调用继承的第一个父类的成员属性、方法;一次类推
super用法?
super本身是一个类,super()是一个对象(在哪个类里调用super()就是哪个类的对象);用于调用父类绑定的方法。
super只调用父类成员属性、方法,例如:
class Father():
property = 'father'
def F_boby(self):
print('father boby')
class Mather():
property = 'mather'
def M_boby(self):
print('mather boby')
class Daughter(Father,Mather):
property = 'Daughter'
def test(self):
print(super().property)
obj = Daughter()
obj.test()
mro()方法返回多继承同名方法调用优先级?
class A():
def public(self):
print("A public 1")
class B(A):
def public(self):
print("B public2")
class C(A):
def public(self):
print("C public3")
class test(B,C):
def public(self):
print("test public4")
super().public()
print("test public5")
obj = test()
print(test.mro())
issubclass判断类继承关系?
class A():
pass
class B(A):
pass
class C(B,A):
pass
class D(C):
pass
#判断D是C的子类
print(issubclass(D,C))
#判断C是B的子类
print(issubclass(C,B))
#判断C是A或B的子类
print(issubclass(C,(A,B)))
#判断C是A或B的子类
print(issubclass(C,(A,B)))
isinstances判断类的类型?
#判断obj是A类的对象
class A():
pass
obj = A()
print(isinstance(obj,A))
类的多态
什么是类的多态?
不通的子类对象,调用相同的父类方法,产生不同的结果叫做类的多态;通俗的讲,多态就是类的继承和子类方法的改写。
实战案例?
Army类和Navy类都继承了Soldier类,但是调用相同的子类方法返回不通的结果。就叫做类的多态。
class Soldier():
#攻击
def attack(self):
pass
#撤退
def back(self):
pass
#陆军
class Army(Soldier):
def attack(self):
print("拼刺刀")
def back(self):
print("撒丫子跑")
#海军
class Navy(Soldier):
def attack(self):
print("潜艇偷袭")
def back(self):
print("开潜艇跑")
obj1 = Army()
obj1.attack()
obj2 = Navy()
obj2.attack()
类的反射
什么是类的反射?
通过字符串去操作类对象或者模块中的成员属性、方法。
通过反射对类对象中的成员进行调用?
hasattr()检测对象/类是否存在指定成员:
class Children():
"""
成员属性:eye
成员方法:skylight、moonread、__makebaby
"""
eye = "血轮眼"
def skylight(self):
print("出生使用天照眼")
def moonread(self):
print("出生使出武功绝学")
obj = Children()
#判断obj对象是否存在eye成员属性
print(hasattr(obj,'eye'))
#判断Children类中是否存在eye成员属性
print(hasattr(Children,'eye'))
getattr()获取类或对象成员属性、方法:
class Children():
"""
成员属性:eye
成员方法:skylight、moonread、__makebaby
"""
eye = "血轮眼"
def skylight(self):
print("出生使用天照眼")
def moonread(self):
print("出生使出武功绝学")
obj = Children()
res = getattr(obj,'skylight')
#通过对象反射出来的方法是绑定方法
res()
#通过类反射出来的方法需要给类传递参数
res1 = getattr(Children,'moonread')
res1(1)
setattr()设置类/对象成员属性、方法:
class Children():
"""
成员属性:eye
成员方法:skylight、moonread、__makebaby
"""
eye = "血轮眼"
def skylight(self):
print("出生使用天照眼")
def moonread(self):
print("出生使出武功绝学")
obj = Children()
#设置对象成员属性的值
setattr(obj,"eye","黑眼")
print(obj.eye)
#设置类方法的值
setattr(Children,'skylight',lambda :print("出生使用红眼"))
Children.skylight()
delattr()删除类/对象成员属性、方法:
class Children():
eye = "血轮眼"
def skylight(self):
print("出生使用天照眼")
def moonread(self):
print("出生使出武功绝学")
obj = Children()
#删除对象成员属性
delattr(Children,'eye')
print(Children.__dict__)
类的装饰器
什么是类的装饰器?
在不修改被装饰函数函数体及函数调用的情况下,使用装饰器函数为被装饰器函数扩展功能。
装饰器的作用?
在不改变原有代码的基础上,实现功能上的扩展。
装饰器的符号?
装饰器使用@符号来代表改函数是一个装饰器函数。
@符号的作用:
- 可以自动把@符号下面的函数当成参数传递给装饰器
- 把新函数返回,让新函数去替换旧函数,实现功能扩展
装饰器基本语法?
装饰器需要传递一个参数,而这个参数就是被装饰函数自己本身。
基本写法:
def warpper(func):
def func1():
print("厕所前,蓬头垢面")
func()
print("厕所后,精神气爽")
return func1
def func():
print("我叫高富帅")
func = warpper(func)
func()
装饰器写法:
def warpper(func):
def func1():
print("厕所前,蓬头垢面")
func()
print("厕所后,精神气爽")
return func1
@warpper #@warpper 等同于 func = warpper(func)
def func():
print("我叫高富帅")
func()
装饰器的嵌套?
嵌套装饰器顺序:装饰前,从上往下;装饰后,从下往上。
从上往下:装饰器func函数前执行顺序
从下往上:装饰器func函数后执行顺序
例如:
def wapper1(func):
def func1():
print("厕所前,人模狗样1")
func()
print("厕所后,牛头马面2")
return func1
def wapper2(func):
def func1():
print("厕所前,洗洗手3")
func()
print("厕所后,洗洗手4")
return func1
@wapper1
@wapper2
def func():
print("我是白富美5")
func()
有参装饰器?
def wapper(func):
def func1(name,age,addr):
print("装饰前1")
func(name,age,addr)
print("装饰后2")
return func1
@wapper
def func(name,age,addr):
print("{name} {age} {addr}".format(name=name,age=age,addr=addr))
func("acai.cloud",27,"BJ")
用装饰器带有参数返回值的函数?
def wapper(func):
def func1(*args,**kwargs):
print("装饰前1")
func(*args,*kwargs)
print("装饰后2")
return func1
@wapper
def func(name,age,addr):
print(name,age,addr)
func("acai",age=27,addr="BJ")
类装饰器?
@wapper.func1相当于obj=Wapper() obj.func1()把对象当成函数进行使用了,自动触发__call__()方法
基本写法:
import time
class Wapper():
def func(self):
print(time.strftime('%Y-%m-%d %H:%M:%S'))
def func():
print("程序运行中……")
func()
obj = Wapper()
obj.func()
装饰器写法:
import time
class Wapper():
def func1(func):
def func2():
print(time.strftime('%Y-%m-%d %H:%M:%S'))
func()
return func2
@Wapper.func1
def func():
print("程序运行中……")
func()
带有参数的类装饰器?
知识点:将类当作函数参数进行传递。
#定义一个类
class test():
aa = 100
#定义一个函数
def func(cls):
obj = cls()
return obj
#把类当成参数传递给func
obj = func(test)
#调用obj成员属性、方法
print(obj.aa)
需求:
如果参数是1,为当前类添加成员属性和方法
如果参数是2,把原run方法变成属性
class Wapper():
ad = "装饰器广告"
def __init__(self,num):
self.num = num
#把对象当作函数使用,需要用call方法
def __call__(self, cls):
if self.num == 1:
return self.func1(cls)
elif self.num == 2:
return self.func2(cls)
def money(self):
print("测试")
#参数为1的情况
def func1(self,cls):
def func():
#为当前cls这个类,添加属性
cls.ad = Wapper.ad
#为当前cls这个类,添加方法
cls.money = Wapper.money
return cls() #返回对象
return func
#参数为2的情况
def func2(self,cls):
def func():
#判断类中有run的方法
if "run" in cls.__dict__:
#调用类中的方法,拿到返回值
res = cls.run()
#把返回值重新赋值给run属性,后者覆盖了前者,方法变成了属性
cls.run = res
return cls()
return func
@Wapper(2)
class MyClass():
def run():
return "亢龙有悔"
obj = MyClass()
print(obj.run)
property装饰器
什么是property装饰器?
可以把类方法转换成属性使用
property装饰器写法?
获取:@property
设置:@属性名.setter
删除:@属性名.deleter
property装饰器应用?
将方法转换为属性:
class MyClass():
def __init__(self,name):
self.name = name
@property #添加property装饰器,将username转换成属性
def username(self):
return self.name
obj = MyClass("acai")
#获取username方法的值
# print(obj.username())
#获取property装饰后,username方法的值
print(obj.username)
设置属性:
class MyClass():
def __init__(self,name):
self.name = name
@property #转换test方法为test属性
def test(self):
print("测试属性")
@test.setter #设置username属性返回值为test属性
def username(self):
return self.name
obj = MyClass("acai")
obj.username
删除属性:
class MyClass():
def __init__(self,name):
self.name = name
@property #转换test方法为test属性
def test(self):
print("测试属性")
@test.deleter
def username(self):
print("删除属性")
obj = MyClass("acai")
obj.username
del obj.username #使用del对象,触发deleter
异常处理
异常处理基本语法?
把可能出现异常的代码放到try代码块中,出现该异常执行except中代码块
基本语法:
try:
代码块
except:
代码块
例如:获取列表index为100的元素,触发try代码块之后,执行except代码块
try:
list1 = [1,2,3,4]
print(list1[100])
except IndexError:
print("获取列表index错误")
处理迭代器异常?
示例:初始化生成器函数,异常处理
def gen():
print(1)
yield 1
print(2)
yield 2
return "test"
try:
test = gen()
test.__next__()
test.__next__()
test.__next__()
except StopIteration as e:
#1. StopIteration 是异常错误类
#2. StopIteration as e 给StopIteration这个类的对象起一个别名e
#3. 打印对象e时,自动触发__str__魔术方法,自动接收return的返回值
print("迭代器取值错误")
print(e)
异常处理的其他写法?
基本语法:
try:
代码块
finally:
代码块
try …… finally …… 介绍:不论代码是否报错,都不许执行的代码放到finally中
try…… finally …… 存在的意义:报错之后,后面的代码就不执行了。所以有些必须要走的代码放到finally中
案例:
try:
list1 = [1,2,3,4]
print(list1[100])
finally:
print("end")
try …… exept …… else ……?
如果try代码没有报错,就执行else这个分支;如果报错就不执行
基本语法:
try:
list1=[1,2,3,4]
print(list1[1])
except:
print("有异常了")
else:
print("正常执行结果……")
主动抛异常 raise?
raise主动抛出异常的实现方式:raise + 异常错误类或者异常错误类对象
所有异常类的父类:BaseException
常规异常类的父类:Exception
raise基本语法:
try:
#主动抛出异常
raise IndexError
except BaseException:
print("异常了")
异常分类?
| IndexError | 索引超出序列的范围 |
|---|---|
| KeyError | 字典中查找一个不存在的关键字 |
| NameError | 尝试访问一个不存在的变量 |
| IndentationError | 缩进错误 |
| AttributeError | 尝试访问未知的对象属性 |
| StopIteration | 迭代器没有更多的值 |
| AssertionError | 断言语句(assert)失败 |
| EOFError | 用户输入文件末尾标志EOF(Ctrl+d) |
| FloatingPointError | 浮点计算错误 |
| GeneratorExit | generator.close()方法被调用的时候 |
| ImportError | 导入模块失败的时候 |
| KeyboardInterrupt | 用户输入中断键(Ctrl+c) |
| MemoryError | 内存溢出(可通过删除对象释放内存) |
| NotImplementedError | 尚未实现的方法 |
| OSError | 操作系统产生的异常(例如打开一个不存在的文件) |
| OverflowError | 数值运算超出最大限制 |
| ReferenceError | 弱引用(weak reference)试图访问一个已经被垃圾回收机制回收了的对象 |
| RuntimeError | 一般的运行时错误 |
| SyntaxError | Python的语法错误 |
| TabError | Tab和空格混合使用 |
| SystemError | Python编译器系统错误 |
| SystemExit | Python编译器进程被关闭 |
| TypeError | 不同类型间的无效操作 |
| UnboundLocalError | 访问一个未eError的子类 |
| UnicodeTranslateError | Unicode转换时的错误(UnicodeError的子类) |
| ValueError | 传入无效的参数 |
| ZeroDivisionError | 除数为零初始化的本地变量(NameError的子类) |
| UnicodeError | Unicode相关的错误(ValueError的子类) |
| UnicodeEncodeError | Unicode编码时的错误(UnicodeError的子类) |
| UnicodeDecodeError | Unicode解码时的错误(UnicodError的子类) |
python网络编程
传统网络架构分为两种:C/S架构、B/S架构
什么是TCP三次握手?
- 客户端向服务器发起连接请求,并且发送SYN假设序列号为J
- 服务器接收到客户端发送过来的SYN后,会返回给客户端一个SYN+ACK的应答;ACK的序列号是J+1表示是给客户端SYN的应答;发送的SYN的序列号是K
- 客户端接收到来自服务器的SYN(序列号为K)+ACK(序列号为J+1)后,给服务器回应ACK K+1表示收到了。然后两边就可以传输数据了。
socket网络模型
什么是socket?
socket(套接字)是用于数据收发的网络工具,支持TCP、UDP协议
tcp socket基本语法?
server:
1. 创建socket对象
sk = socket.socket()
2. 绑定地址及端口,bind方法只接收元组数据类型
sk.bind(('127.0.0.1',8080))
3. 监听socket地址及端口
sk.listen()
4. 建立三次握手,返回conn,addr两个对象
conn,addr = sk.accept()
5. 接收或发送数据,recv参数单位为字节;代表一次最多接收多少字节;socket收发数据只接受二进制字节流,所以发送数据需要将数据编码(sk.send(b'数据'.encode('utf-8'))),接收数据同样需要解码(conn.recv(1024).decode('utf-8'))
#发送数据
conn.send(msg.encode('utf-8'))
#接收数据
conn.recv(1024).decode('utf-8')
6. 关闭tcp连接
conn.close()
7. 关闭端口
sk.close()
client:
1. 创建socket对象
sk = socket.socket()
2. 向server建立连接
sk.connect(('127.0.0.1',8080))
3. client向server发送数据,发送数据时需要将数据转换为二进制字节流
sk.send("acai.cloud".encode('utf-8'))
4. 发送数据完成关闭连接
sk.close()
案例:模拟聊天工具,client向server发送消息server能够收到;server向client发送消息client能收到
server:
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',8080))
sk.listen()
conn,addr = sk.accept()
res = conn.recv(1024)
if len(res) >0:
print(res.decode())
msg = input("input you message:").encode()
if len(msg) >0:
conn.send(msg)
conn.close()
sk.close()
client:
import socket
sk = socket.socket()
sk.connect(('127.0.0.1',8080))
msg = input("input you message:").encode()
if len(msg) >0:
sk.send(msg)
else:
exit(1)
msg_to = sk.recv(1024).decode()
if len(msg_to) >0:
print(msg_to)
udp socket基本语法?
server:
1. 创建socket udp对象,type=socket.SOCK_DGRAM返回udp对象,如果不指定默认tcp对象
sk = socket.socket(type=socket.SOCK_DGRAM)
2. 绑定地址及端口
sk.bind(('127.0.0.1'),8000)
3. 接收消息,udp没有三次握手。所以直接接收消息即可;udp作为server时,第一次一定是接收消息
msg,cli_addr = sk.recvfrom(1024)
4. 关闭连接
sk.close()
client:
1. 创建socket对象,type=socket.SOCK_DGRAM返回udp对象,如果不指定,默认为tcp对象
sk = socket.socket(type=socket.SOCK_DGRAM)
2. 发送数据,发送数据为二进制字节流
sk.sendto(msg.encode(),('127.0.0.1',8080))
黏包
什么是黏包?
接收端不知道发送端要发送字节流的长度,当字节流的长度大于接收端最大接收长度时;把多条数据当成一条数据进行截取造成黏包。通俗的讲:如果接收端接收最大字节流长度为1024,而发送端同时发送多条数据且数据长度小于1024;那么接收端把多条数据当成一条数据接收造成黏包。
什么是缓冲区?
缓冲区用来临时保存数据。为了保证能够完整接收数据,缓冲区的设置都比较大;python获取缓冲区大小如下所示:
import socket
sock = socket.socket()
buf_size = sock.getsockopt(socket.SOL_SOCKET,socket.SO_SNDBUF)
print(buf_size)
为什么会有黏包?
发送端:由于两个数据较短,发送的时间间隔较短。所以再发送端形成黏包;比如两次发送字节流大小小于1024,接收端会把两条数据当成一条数据进行接收
接收端:由于两个数据几乎同时被发送到对方缓存中,所以再接收端形成了黏包。
总结:出现黏包核心原因是tcp对数据无边界截取,不会按照发送的顺序判断。
黏包的使用场景?
对黏包处理可以分为以下两种情况:
- 解决黏包场景:在实时通讯时
- 不需要解决黏包场景:文件传输时
如何解决黏包?
python提供struct模块来解决黏包的问题,该模块提供以下两种方式:
pack:把任意长度的数字转化成具有4个字节的固定长度的字节流
unpack:把4个字节值恢复成原本的数字,返回元组
struct语法:
struck.pack(fmt,*args) 按照给定的格式转换为bytes类型
struck.unpack(fmt, string) 按照给定的格式解析字节流,返回解析结果为元组
struct模块的应用:
1. 将123123转换为bytes类型:
import struct
res = struct.pack('i',123123123)
print(res,len(res))
2. 通过unpack方法对字节流进行解析
res1 = struct.unpack('i',res)
print(res1)
使用struct模块解决黏包?
思路:发送端先给接收端发送数据字节大小,接收端发送数据字节大小之后;第二次接收数据只接受该数据大小的数据包
server:
import socket
import struct
sk = socket.socket()
sk.bind(('127.0.0.1',8080))
sk.listen()
#三次握手
conn,addr = sk.accept()
#处理收发数据逻辑
strvar = input("请输入>>>:")
msg = strvar.encode()
#获取发送数据字节长度
length = len(msg)
#第一次发送字节长度
res = struct.pack('i',length)
conn.send(res)
#第二次发送真实的数据
conn.send(msg)
#四次挥手
conn.close()
#关闭端口
sk.close()
client:
import socket
import struct
sk = socket.socket()
sk.connect(('127.0.0.1',8080))
#处理收发数据逻辑
#接收第一次发送过来的数据
num = sk.recv(4)
tup = struct.unpack('i',num)
num = tup[0]
#第二次发送真实的数据
res1 = sk.recv(num)
print(res1.decode())
#第三次发送的真是数据
res2 = sk.recv(1024)
print(res2.decode())
#关闭连接
sk.close()
socketserver
什么是socketserver?
socketserver简化了socket步骤,且支持tcp多线程并发,多客户端连接。
tcp socketserver基本语法?
server:
import socketserver
class MyServer(socketserver.BaseRequestHandler):
#继承socketserver.BaseRequestHandler类必须要定义一个handle方法
def handle(self):
print("该handle方法被执行……")
server = socketserver.ThreadingTCPServer(("127.0.0.1",8080),MyServer)
#循环调用,来建立连接
server.serve_forever()
client:
import socket
sk = socket.socket()
sk.connect(("127.0.0.1",8080))
sk.close()
案例:通过socketserver实现数据传输?
server:
import socketserver
class MyServer(socketserver.BaseRequestHandler):
#继承socketserver.BaseRequestHandler类必须要定义一个handle方法
def handle(self):
conn = self.request
while True:
#接收数据
msg = conn.recv(1024)
#判断接收的数据是否为空,如果不为空打印数据
if not msg:
pass
else:
print(msg.decode('utf-8'))
server = socketserver.ThreadingTCPServer(("127.0.0.1",8080),MyServer)
#循环调用,来建立连接
server.serve_forever()
client:
import socket
sk = socket.socket()
sk.connect(("127.0.0.1",8080))
while True:
msg = input("请输入要发送的数据>>>>:")
sk.send(msg.encode('utf-8'))
sk.close()
文件校验
hashlib模块?
hashlib这个模块是一堆加密算法的集合体,哈希算法的加密方法不止一种。
hashlib应用场景?
用户密码相关:加密,解密
文件校验相关:加密,解密
hashlib基本用法?
基本语法:
import hashlib
#创建md5算法的对象
hs = hashlib.md5()
#把要加密的字符串通过update更新到hs对象中运算,并且要把字符串转换为二进制字节流
hs.update('12345678'.encode('utf-8'))
res = hs.hexdigest()
print(res,len(res))
加盐?
加一个关键字配合原字符串,让密码更加复杂,不容易破解
案例:
import hashlib
import random
hs = hashlib.md5("XBoy_".encode('utf-8'))
hs.update('123456'.encode('utf-8'))
res = hs.hexdigest()
print(res,len(res))
案例:动态加盐
import hashlib
import random
res = str(random.randrange(100000,1000000))
print(res)
hs = hashlib.md5(res.encode('utf-8'))
hs.update("123456".encode('utf-8'))
res = hs.hexdigest()
print(res)
sha算法?
sha:算出来的十六进制的串是40位,加密稍慢;安全性高
md5:算出来的十六进制的串是32位,加密速度快,安全性一般
sha算法基本语法:
import hashlib
import random
hs = hashlib.sha1()
hs.update("123456".encode('utf-8'))
res = hs.hexdigest()
print(res,len(res))
配合加密算法实现文件校验?
普通文件加密校验:
def check_md5(file):
with open(file, mode='rb') as f:
hs = hashlib.md5()
hs.update(f.read())
return hs.hexdigest()
res1 = check_md5('test/1.txt')
res2 = check_md5('test/2.txt')
print(res1,res2)
针对大文件进行内容校验:
方式一:
def check_md5(file):
hs = hashlib.md5()
with open(file,mode='rb') as f:
while True:
#read(10) 代表一次最多读10个字节
content = f.read(10)
#如果有内容就进行计算
if content:
#分批进行计算,因为分批计算和一次进行计算结果都是一样的
hs.update(content)
else:
break
return hs.hexdigest()
res = check_md5('test/1.txt')
print(res)
方法二:
import hashlib
import os
def check_md5(file):
hs = hashlib.md5()
#计算文件大小返回的字节个数
file_size = os.path.getsize(file)
with open(file,mode='rb') as f:
while file_size:
#一次最多读10个字节
content = f.read(10)
hs.update(content)
#file size每次减去读取的字节数,如果读取的字节数不足10个字节,所以file size每次减content的长度
file_size -= len(content)
return hs.hexdigest()
res = check_md5('test/1.txt')
print(res)
服务器合法性校验
通过模拟支付宝支付接口,实现服务器合法性校验:
server:
import socket
import hmac
import os
def auth(conn,secret_key):
#随记产生32位二进制字节流
msg = os.urandom(32)
#向服务器发送secret_key进行认证
conn.send(msg)
hm = hmac.new(secret_key.encode(),msg,digestmod='md5')
res_hm = hm.hexdigest()
print(res_hm)
res_client = conn.recv(1024).decode('utf-8')
print(res_client)
#权限校验
if res_client == res_hm:
print("是合法用户")
return True
else:
print("不是合法用户")
return False
sk = socket.socket()
sk.bind(('127.0.0.1',8080))
sk.listen()
conn,addr = sk.accept()
#设置密钥
secret_key = '芝麻开门'
res = auth(conn,secret_key)
conn.close()
sk.close()
client:
import socket
import hmac
def auth(sk,secret_key):
#处理权限验证的逻辑
msg = sk.recv(32)
hm = hmac.new(secret_key.encode(),msg,digestmod='md5')
res_hm = hm.hexdigest()
print(res_hm)
#向服务端发送加密字符串
sk.send(res_hm.encode('utf-8'))
secret_key = "芝麻开门"
sk = socket.socket()
sk.connect(('127.0.0.1',8080))
#验证服务端
auth(sk,secret_key)
#发送数据
sk.send("芝麻开门".encode('utf-8'))
sk.close()
进程
进程基础
什么是进程?
进程就是正在运行的程序,它是操作系统中资源分配的最小单位;资源分配,分配的是cpu和内存等物理资源;每个进程都有一个进程号,进程号是进程的唯一标识;同一个进程同时执行两次是两个进程。
进程和进程之间的关系?
进程和进程之间数据彼此隔离,通过socket进行通信。
什么是并行和并发?
并发:一个CPU同一时间不停执行多个程序。
并行:多个cpu同一时间不停执行多个程序。
cpu的调度算法?
先来先服务fscf(first come first server):先来的先执行
短作业优先算法:先把任务短的算完
时间片论转算法:每一个任务就执行一个时间片的时间,然后就执行其他的
多级反馈队列算法:上面三种算法综合体
进程的基本语法?
进程使用的基本语法:
import os
from multiprocessing import Process
def func():
print("子进程id>>>{}, 父进程id>>>{}".format(os.getpid(),os.getppid()))
if __name__ == '__main__':
#创建子进程,返回一个进程对象,这个对象用来执行func任务
p = Process(target=func) #target指定执行的任务
#调用子进程
p.start()
带参数进程的基本语法?
参数描述:
| 参数 | 描述 |
|---|---|
| process | 创建子进程,返回进程的对象 |
| target | 指定要执行的任务 |
| args | 指定传递给要执行任务的函数参数,args的类型是元组,多个参数之间用逗号隔开 |
示例:
import os
from multiprocessing import Process
def func(n):
for i in range(1,n+1):
print("子进程id>>>{}, 父进程id>>>{}".format(os.getpid(),os.getppid()))
if __name__ == '__main__':
n = 5
p = Process(target=func,args=(n,))
#调用子进程
p.start()
for i in range(1,n+1):
print("*" * i)
什么是进程的join?
等待所有子进程全部执行完毕之后,主进程任务再继续执行;如果主进程不等待子进程执行完成再去执行,那么可能会导致主进程执行完成之后程序就终止了。
join的基本语法?
from multiprocessing import Process
def func():
print("发送第一封邮件")
if __name__ == '__main__':
p = Process(target=func)
p.start()
#默认情况下会执行发送第二封邮件,使用join方法。可以实现先发送第一封邮件,再发送第二封邮件
#join的作用是等待子进程执行完成之后,再继续执行主程序中的代码;用来同步代码的一致性
p.join()
print("发送第二封邮件")
多个子进程配合join使用:
思想:等待子进程全部执行完成之后,再使用join阻塞;然后执行主进程。
from multiprocessing import Process
def func(index):
print("发送{}封邮件".format(index))
if __name__ == '__main__':
lst = []
for i in range(10):
p = Process(target=func, args=(i,))
p.start()
lst.append(p)
for i in lst:
i.join()
print("主进程发最后一封邮件,里面的内容是我发完了")
使用自定义类的方式来创建进程?
自定义类创建进程的要求:
- 自定义的类必需继承Process这个父类
- 所有进程执行任务的逻辑要写run方法里面
自定义创建进程的基本语法:
import os
from multiprocessing import Process
class MyProcess(Process):
def run(self):
print("1子进程id>>>{}, 2父进程id>>>{}".format(os.getpid(), os.getppid()),)
if __name__ == '__main__':
p = MyProcess()
p.start()
print("3子进程id>>>{}, 4父进程id>>>{}".format(os.getpid(), os.getppid()), )
自定义类创建有参数的进程基本语法:
import os
from multiprocessing import Process
class MyProcess(Process):
def __init__(self,args):
#手动调用父类的构造方法,实现进程的创建
super().__init__()
self.args = args
def run(self):
print("1子进程id>>>{}, 2父进程id>>>{}".format(os.getpid(), os.getppid()),self.args)
if __name__ == '__main__':
p = MyProcess(1)
p.start()
print("3子进程id>>>{}, 4父进程id>>>{}".format(os.getpid(), os.getppid()), )
守护进程
什么是守护进程?
守护进程就是守护主进程,如果主进程执行结束了,立刻终止程序。
守护进程的基本语法?
进程.daemon=True
进程.daemon=True,必需再start()方法之前
守护进程示例:
from multiprocessing import Process
def func():
print("开始当前子进程……")
print("结束当前子进程……")
if __name__ == '__main__':
p = Process(target=func)
p.daemon = True
p.start()
print("主程序执行结束……")
守护进程的应用场景:
import time
from multiprocessing import Process
def func1():
count = 1
while True:
print("*" * count)
count += 1
def func2():
print("开始当前子进程")
time.sleep(2)
print("结束当前子进程")
if __name__ == '__main__':
p1 = Process(target=func1)
p2 = Process(target=func2)
p1.daemon = True
p1.start()
p2.start()
print("主程序代码结束")
守护进程的实际用途?
监控报活:用用服务器向监控服务器发送信息,告诉监控服务器运行状态
import time
from multiprocessing import Process
#监控报活
def alive():
while True:
print("给监控服务器发消息,验证服务器运行状态")
time.sleep(1)
#当前服务器运行状态
def func1():
while True:
time.sleep(5)
print("当前服务器功能,统计财务报表")
if __name__ == '__main__':
p1 = Process(target=func1)
p2 = Process(target=alive)
p2.daemon = True
p1.start()
p2.start()
#此处join方法的作用是让主进程阻塞,等子进程执行结束后再执行主进程。
p1.join()
print("当前服务器状态……")
进程阻塞
为什么要用进程阻塞?
为了解决多个任务在同一时间抢占同一份资源造成死锁。python中使用semaphore来解决这个问题。
什么是信号量semaphore?
本质上就是进程锁,对进程进行上锁控制。
semaphore基本语法?
import time
from multiprocessing import Process,Semaphore
def KTV(person,sem):
sem.acquire()
#开始唱歌
print("{}进入KTV,正在唱歌".format(person))
time.sleep(3)
print("{}离开KTV,唱完了".format(person))
sem.release()
if __name__ == '__main__':
sem = Semaphore(4)
for i in range(10):
Process(target=KTV,args=("person{}".format(i),sem)).start()
进程事件
什么是进程事件?
进程事件也是用来实现进程阻塞的方式之一,进程使用用Event类来实现
进程事件实现进程阻塞的步骤?
- e= Event()类生成事件对象e
- e.wait()动态给程序加阻塞
- 程序中是否加塞完全取决于该对象中的is_set(),默认返回值是False
- 如果是False进程加塞
控制对象的is_set()值的方法:
| 方法 | 描述 |
|---|---|
| set() | 设置属性值为True |
| clear() | 设置属性值为False |
| is_set() | 判断当前的属性值 |
进程事件Event基本语法?
阻塞事件:在e.wait()后面的代码不会被执行
from multiprocessing import Process,Event
e = Event()
print(e.is_set())
#阻塞返回值默认是False,所以程序会阻塞
e.wait()
print("程序运行中")
阻塞事件:让后面代码执行
from multiprocessing import Process,Event
e = Event()
print(e.is_set())
#设置阻塞返回值为True,所以程序不会被阻塞
e.set()
e.wait()
print("程序运行中")
阻塞事件:阻塞3秒,3秒后执行后面的代码
from multiprocessing import Process,Event
e = Event()
#参数:阻塞时间,如果超过阻塞时间执行后面的代码
e.wait(3)
print("程序运行中")
案例:使用阻塞事件实现模拟红绿灯?
import time
from multiprocessing import Process,Event
def traffic_light(e):
print("红灯亮")
while True:
if e.is_set():
#绿灯状态,亮1秒钟
time.sleep(1)
print("红灯亮了")
#把True 变为False
e.clear()
else:
#红灯状态,亮1秒
time.sleep(1)
print("绿灯亮")
#把False 变成 True
e.set()
if __name__ == '__main__':
e = Event()
Process(target=traffic_light,args=(e,)).start()
进程队列
什么是进程队列?
为了进程和进程之间数据共享
队列queen的特点?
- 先进相处,后进后出
- 如果队列里没有数据,再调用get方法会发生队列阻塞
队列queen的基本语法?
from multiprocessing import Process,Queue
q = Queue()
#1. 往队列中存值
q.put(111)
#2. 从队列中取值
res = q.get()
print(res)
限定Queen队列的长度?
比如:限定Queen队列三个消息,如果队列超出限定队列长度会发生阻塞
from multiprocessing import Process,Queue
q = Queue(3)
q.put(1)
q.put(2)
q.put(3)
q.put(4)
案例:通过进程队列实现主进程与子进程之间数据交换
主进程添加数据,子进程取数据
from multiprocessing import Process,Queue
def func1(q):
#子进程取数据
res = q.get()
print("func1:",res)
def func2(q):
res = q.get()
print("func2:",res)
if __name__ == '__main__':
q = Queue()
p1 = Process(target=func1,args=(q,))
p1.start()
#主进程向队列添加数据
q.put("acai.cloud1")
#为了等待子进程把数据添加到队列再取,否则会发生消息阻塞
p1.join()
print("主进程:{}".format(q.get()))
进程Manager
什么是进程Manager?
进程Manager用于进程之间数据共享,数据可以实列表或字典
进程Manager的基本语法?
from multiprocessing import Process,Manager,Lock
def work(data,lock):
#上锁,等执行完成之后放行
# lock.acquire()
# data["count"] -= 1
# lock.release()
#使用with语法简化上锁解锁操作
with lock:
data["count"] -= 1
if __name__ == '__main__':
mgr = Manager()
data = mgr.dict({"count":200})
lst = []
lock = Lock()
for i in range(100):
p = Process(target=work,args=(data,lock))
p.start()
lst.append(p)
for i in lst:
i.join()
print(data)
生产者和消费者模型
什么是生产者和消费者模型?
可以理解为生产者负责存储数据,消费者负责获取数据
为什么要有生产者和消费者模型?
进程和进程之间数据相互隔离,为了实现进程间通讯
相对列项的生产者和消费者模型:生产者和消费者速度相对均匀
生产者和消费者模型案例?
import time
from multiprocessing import Process,Queue
#消费者模型
def consumer(q,name):
while True:
time.sleep(1)
food = q.get()
print("{name} 吃了{food}个".format(name=name,food=food))
#生产者模型
def producer(q,name,food):
for i in range(1,6):
time.sleep(1)
print("{name} 生产了{food} {num}个".format(name=name, food=food, num=i))
q.put(food+str(i))
if __name__ == '__main__':
#创建队列q
q = Queue()
#创建消费者进程
p1 = Process(target=consumer,args=(q,"acai"))
p1.start()
#创建生产者进程
p2 = Process(target=producer, args=(q,"acai","大白菜"))
p2.start()
print("程序执行结束……")
JoinableQueue队列?
JoinableQueue队列方法:
| 方法 | 描述 |
|---|---|
| put | 存储数据 |
| get | 获取数据 |
| task_done | 队列计数减1 |
| join | 队列阻塞 |
注意:task_done配合join一起使用,用来解决队列长度为0时结束主进程
JoinableQueue队列计数?
| 方法 | 描述 |
|---|---|
| put | 每存放一个值,队列计数加1 |
| get | 通过task_done对计数减1 |
| join | 判断队列时阻塞还是放行,如果计数为0放行队列,其他情况阻塞队列 |
JoinableQueue基本使用?
from multiprocessing import Process,JoinableQueue
jq = JoinableQueue()
#对了计数器加1
jq.put("a")
print(jq.get())
#通过task_done()让对了计数器减1
jq.task_done()
#只有队列计数器为0时,才会放行阻塞
jq.join()
print("finish")
使用JoinableQueue优化生产者消费者模型:
import time
from multiprocessing import Process,JoinableQueue
#消费者模型
def consumer(jq,name):
while True:
time.sleep(1)
food = jq.get()
print("{name} 吃了{food}个".format(name=name,food=food))
#生产者模型
def producer(jq,name,food):
for i in range(1,4):
time.sleep(1)
print("{name} 生产了{food} {num}个".format(name=name, food=food, num=i))
jq.put(food+str(i))
jq.task_done()
if __name__ == '__main__':
#创建队列q
jq = JoinableQueue()
#创建消费者进程
p1 = Process(target=consumer,args=(jq,"acai"))
#设置消费者进程为守护进程,当主进程结束后杀死消费者进程
p1.daemon = True
p1.start()
#创建生产者进程
p2 = Process(target=producer, args=(jq,"acai","大白菜"))
p2.start()
#设置队列阻塞,如果队列长度为0时执行后面的代码;如果队列长度不为0时阻塞
jq.join()
#设置进程阻塞
p2.join()
print("程序执行结束……")
进程知识点总结
进程阻塞:Semaphore、join
进程数据交换:进程Manager、Queue、JoinableQueue
线程
线程基础
什么时线程?
线程时cpu执行程序的最小单位
线程的特点?
- 一个进程资源中可以包含多个线程
- 并发多线程和多线程,多线程速度更快
- 多线程共享同一份进程资源
进程和线程的区别?
进程:用来分配资源的,进程不干活
线程:程序的最小单位,线程是用来干活的
创建线程的基本语法?
import os
from threading import Thread
from multiprocessing import Process
def func(num):
print("当前线程{},所属的进程ID号{}".format(os.getpid(),num))
if __name__ == '__main__':
for i in range(10):
#异步创建10个子线程
t = Thread(target=func,args=(i,))
t.start()
print("主程序执行任务")
用类定义线程?
from threading import Thread
class MyThread(Thread):
def __init__(self,name):
#手动调用父类的构造方法
super().__init__()
self.name = name
def run(self):
print("当前进程正在执行Running……",self.name)
if __name__ == '__main__':
t = MyThread("机器今天会再次爆炸")
t.start()
print("主线程执行结束")
线程相关方法?
| 方法 | 描述 |
|---|---|
| is_alive() | 检测线程是否存在 |
| setName() | 设置线程名字 |
| getName() | 获取线程名字 |
| currentThread().ident | 查看线程ID号 |
| enumerate() | 返回当前正在运行的线程列表 |
| activeCount() | 返回当前正在运行线程数量 |
线程案例?
import os
from threading import Thread,currentThread,enumerate,activeCount
def func():
#查看子线程id
print("子线程id:",currentThread().ident,os.getpid())
if __name__ == '__main__':
for i in range(5):
Thread(target=func).start()
#查看主线程id
print("主线程id",currentThread().ident, os.getpid())
#查看正在运行线程列表
print(enumerate())
#返回当前正在运行线程数量
print(activeCount())
守护线程
什么是守护线程?
等待所有子线程运行完成之后程序终止,守护线程守护的是所有线程
守护线程的基本语法?
from threading import Thread
import time
def func1():
time.sleep(1)
print("我是func1")
def func2():
print("我是func2 start……")
time.sleep(3)
print("我是func2 end……")
if __name__ == '__main__':
t1 = Thread(target=func1)
t2 = Thread(target=func2)
#在start调用之前,设置守护线程
# t1.setDaemon(True)
t1.start()
t2.start()
print("主线程结束……")
线程锁
什么是线程锁?
线程锁也是实现线程阻塞的方式之一,用来解决子线程还没运行完成主线程运行完成导致程序终止的问题
线程锁的特点?
线程锁的优势:保证线程数据安全
线程锁的缺陷:异步线程同时操作同一份数据,导致数据不一致
线程锁的基本语法?
from threading import Lock,Thread
import time
n = 0
def func1(lock):
global n
for i in range(10000):
# lock方式一
lock.acquire()
n += 1
lock.release()
print("子线程func1 n:",n)
def func2(lock):
global n
for i in range(10000):
# lock方式二
with lock:
n -= 1
print("子线程func2 n:",n)
if __name__ == '__main__':
lock = Lock()
t1 = Thread(target=func1,args=(lock,))
t2 = Thread(target=func2,args=(lock,))
t1.start()
t2.start()
print("主线程n:",n)
线程信号量
线程信号量的作用?
线程锁只能上一把锁,而线程信号量可以上多把锁。
注意点:创建线程的时候是异步线程;使用semaphore上锁之后异步变成了同步。
线程信号量基本语法?
from threading import Semaphore,Thread
def func(i,sm):
pass
if __name__ == '__main__':
sm = Semaphore(5)
for i in range(20):
Thread(target=func, args=(i,sm)).start()