常用模块
random
random() 方法返回随机生成的一个实数
import random
print(random.random()) #默认(0,1)----float 大于0且小于1之间的小数
结果:
0.7386919875081359
print(random.randint(1,3)) #[1,3] 大于等于1且小于等于3之间的整数
print(random.randrange(1,3)) #[1,3) 大于等于1且小于3之间的整数
print(random.choice([1,'23',[4,5]])) #1或者23或者[4,5]
print(random.sample([1,'23',[4,5]],2)) #列表、元素任意2个组合
print(random.uniform(1,3))#大于1小于3的小数,如1.927109612082716
item=[1,3,5,7,9]
random.shuffle(item) #打乱item的顺序,相当于"洗牌"
print(item)
[3, 1, 7, 5, 9]
生成随机验证码
def make_code(n):
res=''
for i in range(n):
s1=chr(random.randint(65,90)) #65,90是ASCII中的大写
s2=str(random.randint(0,9))
s3=chr(random.randint(97,122)) #97,122是ASCII中的小写
res+=random.choice([s1,s2,s3])
return res
print(make_code(7))
os模块
import os
获取文件目录
os.path.dirname(r'D:\pycharm_20期\day6\练习.py')
获取文件名
os.path.basename(r'D:\pycharm_20期\day6\练习.py')
拼接
os.path.join
获取当前目录的父目录字符串名:('..')
os.pardir
规范化路径,如..和/
os.path.normpath
举例
a='/Users/jieli/test1/\\\a1/\\\\aa.py/../..'
print(os.path.normpath(a))
/Users/jieli/test1
获取当前执行文件的最上层文件夹
D:\pycharm_20期\day6\练习.py
BASE_DIR=os.path.normpath(os.path.join(
os.path.abspath(__file__),
os.path.pardir,
os.path.pardir,
))
这种写法的通用性好
sys 模块
import sys
sys.argv
#获取一个List,第一个元素是程序本身绝对路径
#举例,可以这样用:
#当py文件按照脚本方式执行时,可以在py文件后面加上值,此时可以利用sys.argv获取这些值
python3 test.py sfile dfile #脚本方式执行,执行文件后面跟了两个参数
#使用解压方法可以一次将两个参数分别赋予变量
_,sfile,dfile=sys.argv
即:
sfile=sfile #第一个参数
dfile=dfile #第二个参数
sys.exit(n) 退出程序,正常退出时exit(0)
print(sys.path) 初始化时使用PYTHONPATH环境变量的值
使用举例:
把当前目录加入到环境变量
BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
知识点:进度条
先打印出进度条的样子
print('[%-50s]' %('#'*1)) #-代表左对齐,50代表宽度
print('[%-50s]' %('#'*2))
print('[%-50s]' %('#'*3))
结果:
[# ]
[## ]
[### ]
我们要把它变成一个连续的过程
知识点:
%% 两个百分号连到一起代表取消%的特殊意义,第一个百分号就是一个单纯的符号
print('[%%-%ds]' %50)
结果:(是个字符串)
[%-50s]
print(('[%%-%ds]' %50) %('#'*10)) 等于'[%-50s]' %('#'*10)
结果:
[########## ]
实现进度条代码,这里使用time.sleep(0.1)模拟网络延迟
import time
def progress(percent,width=50): #percent是百分比,width是宽度
if percent >= 1:
percent=1
show_srt=('[%%-%ds]' %width) %('#'* int(width*percent)) #宽度乘百分比利用int取整
print('\r%s %d%%' %(show_srt,int(100*percent)),end='') #\r代表光标移动到行首,end=''代表print不换行,%d%%是最后面的百分比
recv_size=0 #已经接收的大小
total_size=102312 #文件总大小
while recv_size < total_size:
time.sleep(0.1)
recv_size+=1024
progress(recv_size/total_size)
这里有个问题,如果文件大小是10241的话,那意味着在循环10次后recv_size已经是10240了,但此时recv_size仍然小于total_size
这时就会再次进入循环,结果在10240即基础上又加上了1024,此时recv_size已经大于total_size,在做除法运算时结果会大于1
这就会导致最后一次计算出的#打印个数大于宽度,需要在上面的进度条显示逻辑做判断,大于1直接按1算
shutil模块
高级的 文件、文件夹、压缩包 处理模块
import shutil
将文件内容拷贝到另一个文件中shutil.copyfileobj(open('old.xml','r'), open('new.xml', 'w'))
shutil.copyfile(src, dst)
拷贝文件shutil.copyfile('f1.log', 'f2.log') #目标文件无需存在
shutil.copy(src, dst)
拷贝文件和权限shutil.copy('f1.log', 'f2.log')
shutil.copytree(src, dst, symlinks=False, ignore=None)
递归的去拷贝文件夹shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))
目标目录不能存在,注意对folder2目录父级目录要有可写权限,ignore的意思是排除
shutil.rmtree(path[, ignore_errors[, onerror]])
递归的去删除文件shutil.rmtree('folder1')
shutil.move(src, dst)
递归的去移动文件,它类似mv命令,其实就是重命名。shutil.move('folder1', 'folder3')
shutil.make_archive(base_name, format,...)
创建压缩包并返回文件路径,例如:zip、tar
base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,
如 data_bak =>保存至当前路径
如:/tmp/data_bak =>保存至/tmp/
format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
root_dir: 要压缩的文件夹路径(默认当前目录)
owner: 用户,默认当前用户
group: 组,默认当前组
logger: 用于记录日志,通常是logging.Logger对象
shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的
将/data下的文件打包放置当前程序目录
import shutil
ret = shutil.make_archive("data_bak", 'gztar', root_dir='/data')
将/data下的文件打包放置 /tmp/目录
import shutil
ret = shutil.make_archive("/tmp/data_bak", 'gztar', root_dir='/data')
解压
import tarfile
t=tarfile.open('/tmp/egon.tar','r')
t.extractall('/egon')
t.close()
josn模块
josn 是一种通用的标准格式
import json
序列化
使用dumps进行序列化
a={'name':'dzm','age':18,'sex':'male'}
with open('user.json','w',encoding='utf-8') as f:
user=json.dumps(a)
f.write(user)
使用dump可以直接将序列化后的内容写入文件json.dump(a,open('user.json','w',encoding='utf-8'))
反序列化
使用loads进行反序列化
with open('user.json','r',encoding='utf-8') as f:
user=json.loads(f.read()) #与json.dumps对应
print(user['name'])
无论数据是怎样创建的,只要满足json格式,就可以json.loads出来,不一定非要dumps的数据才能loads
使用load进行反序列化 load只能读文件
user=json.load(open('user.json','r',encoding='utf-8'))
print(user['name'])
pickle 模块
可以识别python所有的数据类型,但不能跨平台
等号右边任何值都可以被pickle序列化,python中一切皆对象
pickle序列化后的数据是bytes类型,因此写入读取文件时要以b模式打开
import pickle
使用格式与josn相同
序列化
a={'name':'dzm','age':18,'sex':'male'}
res=pickle.dumps(a)
print(res)
直接写入文件pickle.dump(a,open('user.pkl','wb'))
反序列化pickle.loads(res)
从文件读
res=pickle.load(open('user.pkl','rb'))
print(res)
shelve模块
shelve模块比pickle模块简单,只有一个open函数,返回类似字典的对象,可读可写;key必须为字符串,而值可以是python所支持的数据类型
import shelve
写
f=shelve.open('db.shl')
f['stu1']={'name':'dzm','age':18}
f['stu2']={'name':'egon','age':28}
f.close()
读
f=shelve.open('db.shl')
print(f['stu1']['name'])
f.close()
xml模块
from xml.etree import ElementTree
tree=ElementTree.parse('a.xml') #得到根
拿到一个元素Element
root=tree.getroot()
元素
每一个元素都有三个需要掌握的点
root.tag #标签的名字
root.attrib #标签的属性,就是名字后面的内容,如果有属性会把属性变成字典返回
root.text #文本,一个标签内部,在子标签之外的独立文本才算
三种查找方式
从当前节点下面的子节点中找元素Element
root.find() #只找第一个,有多个相同名称的标签也只找一个
root.findall() #全部相同名称的找出来
从整个树形结构中查找
root.iter()
遍历文档数
for country in root: #找根下面的子节点(元素)
for item in country: #再找子节点下面的子节点(元素)
print(item.tag,item.attrib,item.text)
修改内容
把year找到并修改,添加树形,修改文本
for year in root.iter('year'):
year.set('updated','yes') #往文件里写必须是字符串
year.text=str(int(year.text)+1) #在原有年份上加1,取出来的年份是字符串,没法做数学运算,转换+1后要再转换会字符串写入文件
tree.write('a.xml')
添加内容
添加到名为rank的标签下面
for rank in root.iter('rank'):
if int(rank.text) == 5: #取出来的rank.text是字符串,所以转换成int再比较
obj=ElementTree.Element('dzm')
obj.attrib={'name':'dzm','age':'18'} #直接使用attrib添加要全部拼好
obj.text='dzm is good'
rank.append(obj)
tree.write('a.xml')
configparser模块
import configparser
config=configparser.ConfigParser() #得到一个对象
config.read('my.ini') #读取文件,这里使用mysql配置文件模拟
查找
print(config.sections()) #查看有哪些标签
['mysqld', 'client', 'egon']
print(config.options('mysqld')) #查看标签下面的内容,返回的是k
['charater-server-set', 'default-engine', 'skip-grant-table', 'port', 'data_dir']
print(config.get('mysqld','charater-server-set')) #查看标签下面配置项的值
utf8
注意,文件中有一行配置项的值是True,但通过get取出来的True只是一个字符串
print(type(config.get('mysqld','skip-grant-table')))
使用getboolean可以直接转换成布尔值print(config.getboolean('mysqld','skip-grant-table'))
同理,使用getint可以直接获取int类型的值print(config.getint('mysqld','port'))
使用getfloat可以直接拿到浮点型config.getfloat('mysqld','port')
查看一个标签那面有没有这个配置项
print(config.has_option('mysqld','aaa'))
False
添加内容
config.add_section('dzm')
config.set('dzm','name','18') #标签、配置项、值
config.write(open('my.ini','w',encoding='utf-8'))
修改内容
config.set('client','password','870911')
config.write(open('my.ini','w',encoding='utf-8'))
hashlib模块
https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014319556588648dd1fb0047a34d0c945ee33e8f4c90cc000
Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等
hash:一种算法 ,3.x里代替了md5模块和sha模块
import hashlib
m=hashlib.md5()
m.update('hello'.encode('utf-8')) #添加校验文本内容
m.update('world'.encode('utf-8')) #两行内容会自动变为一行
print(m.hexdigest()) #得出哈希值
sha512 算法更复杂
m=hashlib.sha512()
m.update('hello'.encode('utf-8'))
print(m.hexdigest())
hmac模块
用法与hashlib相同,但强制密码加严
import hmac
m=hmac.new('密码加严'.encode('utf-8'))
m.update('hello'.encode('utf-8'))
print(m.hexdigest())
subprocess 模块
创建附加进程
import subprocess
import time
subprocess.Popen('tasklist',shell=True) #创建一个子进程执行,会直接执行下面的代码,不会管这条命令是否执行成功
time.sleep(1) #上面的命令默认将结果打印到终端,但需要一定时间,如果这里不暂停1秒结束程序的话就看不到返回结果
obj=subprocess.Popen('tasklist',shell=True,
stdout=subprocess.PIPE, #创建一个管道,把正确的结果传进这个管道
stderr=subprocess.PIPE, #再创建一个管道,把执行错误的结果传进
)
print(obj.stdout.read().decode('gbk')) #把stdout管道中的东西打出来
print(obj.stderr.read().decode('gbk')) #把stderr管道中的内容打印出来
注意,管道里是bytes类型,需要解码,在windows平台默认是按照gbk编码的,所以要以gbk解码
数据流交互
obj1=subprocess.Popen('tasklist',shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
obj2=subprocess.Popen('findstr python',shell=True,
stdin=obj1.stdout, #数据来源是上一个数据流
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
print(obj2.stdout.read().decode('gbk'))
结果:一个数据流可以和另外一个数据流交互,可以通过爬虫得到结果然后交给greppython.exe 12336 Console 8 11,084 K
类的定义与使用
类的定义
对象是特征与技能的结合体,类就是一系列对象相似的特征与技能的结合体
在现实世界中:一定是先有的一个个具体存在的对象,后总结出的类
在程序中:一定保证先定义类,后产生对象
站在老男孩学校的角度
现实中的对象:
对象1:
特征
学校=老男孩
名字=李三炮
性别=男
年龄=18
技能
学习
选课
对象2:
特征
学校=老男孩
名字=张铁蛋
性别=女
年龄=38
技能
学习
选课
对象3:
特征
学校=老男孩
名字=武大郎
性别=男
年龄=28
技能
学习
选课
对象4:
特征
学校=老男孩
名字=egon
性别=男
年龄=18
技能
教学
现实中的老男孩学生类:
老男孩学生类
相似的特征
学校=老男孩
相似的技能
学习
选课
类的使用
类体代码在类的定义阶段就会立刻执行,
class Student:
school='oldboy'
def learn(self):
print('is learning')
def choose_course(self):
print('choose course')
查看
print(Student.school) #类的数据属性
print(Student.learn) #类的函数属性
增加
Student.name='dzm'
print(Student.name)
修改
Student.school='Oldboy'
print(Student.school)
#删除
del Student.name
print(Student.name)
print(Student.learn) #就是一个函数
Student.learn('xxxxx') #加括号打印,但要遵循类的规则,必须有传参
对象的定义与使用
class Student:
school='oldboy'
def __init__(self,name,age,sex): #在调用类时会自动触发执行
self.Name=name
self.Age=age
self.Sex=sex
def learn(self):
print('is learning')
def choose_course(self):
print('choose course')
调用类的过程又称之为实例化,先定义类,在定义对象
1、得到一个返回值,即对象,该对象是一个空对象
2、Student.init(stu1,'dzm',18,'male)
对象定义过程中其本身会作为第一个值传给函数init,就是那个self
stu1=Student('dzm',18,'male')
stu2=Student('egon',28,'male')
stu3=Student('alex',38,'male')
print(stu1.__dict__) #看看stu1的名称空间里都有什么
{'Name': 'dzm', 'Age': 18, 'Sex': 'male'}
#修改
stu1.Age=19
print(stu1.Age)
#对象的增删改查方式与类的增删改查相同
对象的属性查找
class Student:
school='oldboy'
# Name='xxx'
def __init__(self,name,sex,age): #在调用类时会自动触发执行
self.Name = name
self.Sex = sex
self.Age = age
#stu1.Name='李三炮'
#stu1.Sex='男'
#stu1.Age=18
def learn(self,x,y):
print('%s is learning' %self.Name)
print(x,y)
def choose_course(self):
print('choose course')
def commit_hw(): #类内定义的函数默认要有一个参数,约定俗成地写出self
print('commit homework')
1、查找一个对象的属性顺序是:先找对象自己的dict,再找类的dict
stu1=Student('dzm','男',18)
print(stu1.school)
oldboy
stu1=Student('李三炮','男',18)
stu2=Student('张铁蛋','女',38)
stu3=Student('武大郎','男',28)
2、类的数据属性是所有对象共享,所有对象都指向同一个内存地址
Student.school='Oldgirl' #修改要从类入手
print(Student.school,id(Student.school))
print(stu1.school,id(stu1.school))
print(stu2.school,id(stu2.school))
print(stu3.school,id(stu3.school))
对象的绑定方法
类是一系列对象相似的特征与技能的结合体
#抽象的理解上面掌握了特征,下面要掌握技能
类中定义的函数是绑定给对象使用:
1:不同对象就是不同绑定方法
2:绑定给谁,就应该由谁来调用,谁来调用就会把谁当做第一个参数传给对应的函数
print(Student.learn) #返回结果就是个函数
print(stu1.learn()) #绑定方法,会将对象自动传值给第一个位置参数
stu1.learn()
stu2.learn()
stu3.learn()
调用结果:
李三炮 is learning
张铁蛋 is learning
武大郎 is learning
stu1.learn(1,2) #Student.learn(stu1,1,2)
可以多传几个参数
stu1.commit_hw()
这里调用就会出错,因为绑定到对象的方法有自动传值的特征,而上面类中相应函数没有定义位置参数,所以执行调用会报错