python-模块
模块基本知识
内置模块,python内部提供的功能。
第三方模块,下载/安装/使用。
\# 把pip.exe 所在的目录添加到环境变量中。
pip install 要安装的模块名称 # pip install xlrd
7.1 自定以模块
-
定义:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀。封装语句的最小单位,本质就是.py文件。
-
自定义模块:实际上就是定义.py,其中可以包含:变量定义,可执行语句,for循环,函数定义等等,它们统称模块的成员。(模块本身不宜过大,便于维护)
-
一个py文件拆分100文件,100个py文件又有相似相同的功能.冗余. 此时你要将100个py文件中相似相同的函数提取出来, input 功能,print()功能, time.time() os.path.....放在一个文件,当你想用这个功能拿来即用.类似于这个py文件: 常用的相似的功能集合.模块.
模块就是一个py文件常用的相似的功能集合.
1.为什么要有模块
-
拿来主义,提高开发效率.
-
便于管理维护.
2.模块的分类
1.内置模块200种左右,python解释器自带的模块,time os sys hashlib等等。
2.第三方模块6000种左右,pip install 需要这个指令安装的模块,Beautiful_soup,request,Django,flask 等等。
3.自定义模块,自己写的一个py文件。
4.py文件的两个功能
-
当脚本运行
-
当模块被别人用
3.模块的运行方式
-
脚本就是py文件.长期保存代码的文件.
-
脚本的运行方式:直接用解释器执行。或者PyCharm中右键运行。
-
模块方式:被其它的模块导入。为导入它的模块提供资源(变量,函数定义,类的定义等)
4.__name__属性的使用:
-
在脚本方式运行时,
__name__是固定的字符串:__main__ -
在以模块方式导入时,
__name__就是本模块的名字。 -
在自定义模块对
__name__进行判断,决定是否执行可执行语句:开发阶段,就执行,使用阶段就不执行。
def change():
global name
name = 'barry'
print(name)
# print(__name__)
# 当tbjx.py做脚本: __name__ == __main__ 返回True
# 当tbjx.py做模块被别人引用时: __name__ == tbjx
# __name__ 根据文件的扮演的角色(脚本,模块)不同而得到不同的结果
#1, 模块需要调试时,加上 if __name__ == '__main__':
# import time
# change() # 测试代码
# if __name__ == '__main__':
# change()
# 2, 作为项目的启动文件需要用.
-
一个python的文件有两种使用的方法,第一是直接作为脚本执行,第二是import到其他的python脚本中被调用(模块重用)执行。因此if name == 'main': 的作用就是控制这两种情况执行代码的过程,在if name == 'main': 下的代码只有在第一种情况下(即文件作为脚本直接执行)才会被执行,而import到其他脚本中是不会被执行的。
5.系统的导入模块的路径
-
内存中:如果之前成功导入过某个模块,直接使用已经存在的模块。
-
内置路径:安装路径下:Lib,site-packages
-
PYTHONPATH:import的时候寻找模块的路径 (不使用,易出现重名的问题,污染解释器路径)
-
-
sys.path:是一个路径的列表(用C语言集成到解释器中的,找不到的,没有提供源码。)
-
如果三个都找不到,就报错。
-
动态修改sys.path 。
-
os模块下的
os.path.dirname()获取某个路径的父路径。通常用于获取当前模块的相对路径。
-
-
import sys
import os
sys.path.append(os.path.dirname(__file__) + '/模块目录')
-
模块的四行
# #上来写四行:
def main():
pass
if __name__ == '__main__':
main()
6.improt的使用
-
improt (模块名) ,执行一次(模块)里面的所有类容。
-
第一次引用(模块名)这个模块,会将这个模块里面的所有代码加载到内存,只要你的程序没有结束,接下来你在引用多少次,它会先从内存中寻找有没有此模块,如果已经加载到内存,就不在重复加载.
-
第一次导入模块执行三件事【重要】
-
在内存中创建一个以(模块名)命名的名称空间。
-
执行此名称空间所有的可执行代码(将.py文件中所有的变量与值的对应关系加载到这个名称空间)。
-
通过【模块名.】的方式引用模块里面的代码.
-
import tbjx
print(tbjx.name)
tbjx.read1()
-
被导入模块有独立的名称空间 ***
import tbjx
# name = 'alex'
# print(name)
# print(tbjx.name)
#
# def read1():
# print(666)
# tbjx.read1()
#
# name = '日天'
# tbjx.change()
# print(name) # 日天
# print(tbjx.name) # barry
7.导入模块的多种方式:(有用的是其中的成员)
-
import xxx: 导入一个模块的所有成员.
-
import aa,bb,cc 一次导入多个模块的成员(不建议,建议分开写(方便我们排错))
-
mport os,sys 黄金搭档
-
from xxx import a:从某个模块中导入指定的成员。
-
可以节省空间。
-
-
from xx import a,b,c: 从某个模块中导入多个指定的成员。
-
from xxx import * :从模块中导入所有成员。
-
from 这种方式易导致命名冲突(谁离得近,使用谁
age = 1000
from my_module import age
print(age) #10
from my_module import age
age = 1000
print(age) #1000
-
import xx 与from xxx import *的区别:
-
功能是一样的。
-
使用略有差别:
-
第一种方式,使用成员时,模块名作为前缀。不容易产生命名冲突。
-
第二种方式,无需指定模块名,直接使用成员名。容易产生命名冲突。在后定义的成员生效,把前面的覆盖了。
-
-
8.怎么解决名称冲突的问题:
-
改用import xxx这种方式导入。
-
自己避免使用重名的名称。
-
使用别名解决 √
9.使用别名:alias(as是alias的缩写,别名)【重要】
-
针对的导入的模块和导入的成员
-
给成员起别名(避免名称冲突)
age = 1000
from my_module import age as a
print(age) # 1000
print(a) # 10
-
给模块起别名(简单,便捷)
import my_module as m
print(m.age)
-
有利于代码的简化.
-
# 原始写法
# result = input('请输入')
# if result == 'mysql':
# import mysql1
# mysql1.mysql()
# elif result == 'oracle':
# import oracle1
# oracle1.oracle()
# list.index()
# str.index()
# tuple.index()
# 起别名
# result = input('请输入')
# if result == 'mysql':
# import mysql1 as sm
# elif result == 'oracle':
# import oracle1 as sm
# ''' 后面还有很多'''
# sm.db() # 统一接口,归一化思想
10.from xxx import * 控制成员被导入
from tbjx import *
# # 一般千万别么这写,必须要将这个模块中的所有名字全部记住
# # 但是可以配合一个变量__all__使用
-
默认情况下,所有成员都会被使用。
__all__是一个列表,用于表示模块可以被外界使用的成员,元素是成员名字符串。一般是与 *配合使用。__all__只针对from 这种方式。__all__ = ['age',
'age2',
]
使用import xxx绕过
__all__的限制
11.相对导入 (含有路径,. 这种就是相对导入 路径中也可能有模块名)
-
针对某个项目中的不同模块之间进行导入,称为相对导入。
-
只有一种格式:
from 相对路径 import xxx
相对路径:包含了点号的一个相对路径
. 表示当前路径 from . import abc
..表示上一级路径/父路径
...表示父路径所在的父路径
yy.py 作为外界的入口
# 相对导入同项目下的模块
# from ..z import zz (这种方式不好,向外界暴露zz这个模块的存在)
from ..z.zz import * #这样可以隐藏 幕后提供资源的这帮py文件
# 定义自己的成员
age2 = 888
def f2():
print('f2')
zz.py
'''
项目中,子模块(被相对导入)
'''
age = 10
def f():
print('hello')
"""
测试相对导入
"""
import os
import sys
# 把项目所在的父路径加到sys.path
sys.path.append(os.path.dirname(__file__))
from xx.y import yy
print(yy.age2)
# 如何使用zz里面的成员
# print(yy.zz.age)
# print(yy.zz.f())
#这样的效果就是 yy和zz在一起,
print(yy.age)
yy.f()
-
使用绝对路径做相对导入
yy.py
import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(__file__)) + '/z')
from zz import *
-
模块的搜索路径
***
# import sm
import abc
# python 解释器会自动将一些内置内容(内置函数,内置模块等等)加载到内存中
import sys
# print(sys.modules) # 内置内容(内置函数,内置模块等等)
import time
# print(sys.path)
#['D:\\python_22\\day17', 'C:\\Python\\Python36\\python36.zip', 'C:\\Python\\Python36\\DLLs', 'C:\\Python\\Python36\\lib', 'C:\\Python\\Python36', 'C:\\Python\\Python36\\lib\\site-packages']
# 'D:\\python_22\\day17' 路径是当前执行文件的相对路径
# import tbjx
# 我就想找到dz 内存没有,内置中,这两个你左右不了,sys.path你可以操作.
import sys
sys.path.append(r'D:\python_22\day16')
# sys.path 会自动将你的 当前目录的路径加载到列表中.
import dz
# 如果你想要引用你自定义的模块:
# 要不你就将这个模块放到当前目录下面,要不你就手动添加到sys.path
-
import sm
-
它会先从内存中寻找有没有已经存在的以sm命名的名称空间.
-
它会从内置的模块中找. time,sys,os,等等.
-
他从sys.path中寻找.
-
7.2.1 random 提供了和随机数获取相关的方法
-
此模块提供了和随机数获取相关的方法:
-
random.random():获取从[0.0 , 1.0) 范围内的浮点数。
improt random
print(random.random())
-
random.randint(a,b): 获取[a,b] 范围内的整数。
print(random.randint(3,10))
-
random.uniform(a,b):获取[a,b) 范围内的浮点数。 )取决于操作系统
print(random.uniform(3,5))
-
random.shuffle(x):把参数指定的数据中的元素打乱,其中参数必须是可变数据类型。混洗。 (直接修改原列表)
lst = list(range(10))
random.shuffle(lst)
print(lst)
-
**random.sample(x,k):从x中随机取k个数据,组成一个列表返回。 (从不可变数据类型中取)(变相打乱元组,数据)
t = (1,2,3)
lst = random.sample(t,len(t))
print(lst)
# 应用
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)
import random # 导入一个模块
v = random.randint(起始,终止) # 得到一个随机数
7.2.2 time 表示的是和时间有关的操作
关于时间格式的博客 https://www.cnblogs.com/clschao/articles/10757374.html
-
time模块表示的是和时间有关的操作。
-
time():返回的是从时间原点(1970-01-01 00:00:00)到现在所经历的秒数,即:当前的时间戳(timestamp)。
improt time
print(time.time()) # 1558352285.0049875
-
gmtime([seconds]):返回一个以元组形式的结构化时间对象(struct_time),,参数是表示从时间原点开始经过的秒数.默认使用当前的时间戳,即: time() 的返回值。
# 获取格式化时间对象:是九个字段组成的。
# 默认参数是当前系统时间的时间戳。
improt time
print(time.gmtime()) # GMT:格林尼治平时,世界时(全写为 Greenwich Mean Time)
print(time.gmtime(1)) # 时间元年过一秒后,对应的时间对象
-
localtime([seconds]) :和gtime作用相似,只是结果中的某些字段转换成了本地格式。
import time
t1 = time.localtime() # 本地时间
print(t1)
-
mktime(t) :和localtime是相反的操作.参数是一个格式化时间对象,返回值表示的是这个时间对象相对时间原点的秒数。
import time
t1 = time.localtime() # 时间对象
t2 = time.mktime(t1) # 获取对应的时间戳
print(t2) # 1558352285.0
-
time模块中的三大对象
时间戳,结构化时间对象,字符串是time模块中非常重要的三大对象.
其中:时间戳和结构化时间对象利于在不同的时区之间进行传播(即:国际化),但是不利于阅读.
字符串便于阅读.但是不利于国际化.
结构化时间对象看起来像一个元组,一共有九个属性字段,可以单独使用其中的属性值.
import time
lt = time.localtime()
print(lt.tm_year) # 2019
print(lt.tm_mon) # 5
-
具体字段的取值范围如下表:
-
strftime(format[, tuple]) -> string
第一个参数是一个字符串形式的格式.其中包含一些特殊字符,表示最终要显示的字段.
第二个参数表示的是对哪个结构化时间对象进行转换.默认是当前系统时间对应的时间对象.
-
常用的时间格式中的特殊字符:
%Y Year with century as a decimal number.
%m Month as a decimal number [01,12].
%d Day of the month as a decimal number [01,31].
%H Hour (24-hour clock) as a decimal number [00,23].
%M Minute as a decimal number [00,59].
%S Second as a decimal number [00,61].
-
例如:
import time
t = time.strftime('%Y-%m-%d %H:%M:%S') # 把当前时间转换成指定格式的字符串
print(t) # '2019-04-30 14:59:57'
-
strptime(string, format) -> struct_time
第一个参数是表示时间的字符串,第二个参数是和这个字符串相对应的格式字符串.最终得到的是一个结构化时间对象。
import time
s = time.strptime('2019-04-30 14:59:57','%Y-%m-%d %H:%M:%S')
print(s)
# 结果:
# time.struct_time(tm_year=2019, tm_mon=4, tm_mday=30, tm_hour=14, tm_min=59,tm_sec=57, tm_wday=1, tm_yday=120, tm_isdst=-1)
# tm_isdst = 1 的时候表示时间是夏令时,值为0的时候表示非夏令时值为-1的时候表示时间不确定是否是夏令时 .
-
sleep(seconds):暂停当前正在执行的程序指定的秒数,然后继续执行,参数可以是浮点数。
import time
for x in range(5):
time.sleep(1)
print(time.strftime('%Y-%m-%d %H:%M:%S'))
7.2.3 datetime用来操作时间日期和对象
-
此模块用来操作时间日期和对象,主要用于对属性的抽取和计算上。
-
date :日期,包含year,month,day三个属性.
import datetime
# date类:
d = datetime.date(2010,10,10)
print(d)
# 获取date对象的各个属性
print(d.year)
print(d.month)
print(d.day)
-
time :时间,包含hour,minute,second,microsecond,tzinfo属性.
import datetime
# time类:
t = datetime.time(10,48,59)
print(t)
# time类的属性
print(t.hour)
print(t.minute)
print(t.second)
-
datetime :前两者的混合体.
import datetime
dt = datetime.datetime(2010,11,11,11,11,11)
print(dt)
-
timedelta :(时间增量),主要用来在某些属性上进行数学运算.
import datetime
td = datetime.timedelta(days=1)
print(td)
import datetime
data = datetime.timedelta(days=-1)
today = datetime.datetime.now()
ret = (today+ data).strftime('%Y-%m-%d')
print(ret) # 获取前一天的时间
datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0,
hours=0, weeks=0)
格式说明:其参数默认都为0,真正存储的只有前三个参数,即:剩余的参数如果提供的话,会被转换成前三个单位的相
应数值来进行存储和表示:
milliseconds -> microseconds (1毫秒 = 1000微秒)
minutes -> seconds
hours -> seconds
weeks -> days
-
即:查看一个timedelta对象的属性值,只能查看在创建timedelta对象时使用的那些属性,后四个属性会转换成前三
个中对应的属性.比如:用weeks表示的一个时间段,则只能查看它对应的天数,而不能查看它对应的秒数。
-
timedelta的主要属性:
| days | 表示时间差对应的天数 |
|---|---|
| seconds | 表示时间差对应的秒数 |
| microseconds | 表示时间对应的微秒数 |
import datetime
x = datetime.timedelta(days=1)
print(x.seconds) # 0
print(x.days) # 1
print(x.microseconds) # 0
-
后四个单位可以转换成对应的单位.
import datetime
x = datetime.timedelta(hours=2)
print(x.days) # 0
print(x.seconds) # 7200
-
时间段运算
虽然直接对时间段的属性查看有限制,但是如果时间段是经过计算得到的,则结果中时间段的属性查看范围是参与计算
的时间段对象的属性的并集.
-
例如:用days和seconds创建的时间段对象的计算结果,两种属性都能查看
import datetime
td1 = datetime.timedelta(days=2)
td2 = datetime.timedelta(seconds=1800)
td3 = td1 - td2
print(td3.days) # 1
print(td3.seconds) # 84600
print(td3.microseconds) # 0
-
但是,用hours和seconds创建的时间段对象的计算结果,就只能查看seconds属性.
import datetime
td1 = datetime.timedelta(hours=1)
td2 = datetime.timedelta(seconds=1000)
td3 = td1 - td2
print(td3.days) # 0
print(td3.seconds) # 2600
print(td3.microseconds) # 0
练习题
1.计算三天前的日期
>>> now = datetime.datetime.now() # 获取当前日期和时间
>>> now
datetime.datetime(2019, 5, 5, 15, 37, 23, 289235)
>>> delta = datetime.timedelta(days=3) # 定义一个时间段,用于表示三天
>>> res = now - delta # 计算时间
>>> res
datetime.datetime(2019, 5, 2, 15, 37, 23, 289235)
>>> res.strftime('%Y-%m-%d') # 格式化
'2019-05-02'
-
计算任意年份的2月份的天数
import datetime
year = int(input('输入一个合法年份:'))
# 构建某年的3月1日日期对象
t = datetime.date(year,3,1)
# 创建时间差
delta = datetime.timedelta(days=1)
# 计算二者差值
res = t - delta
# 获取日期
print(res.day)
7.2.4 os:操作系统相关的数据
-
os.remove(file_path) :删除文件
-
os.rmdir(dir_path) :删除空文件夹
-
删除非空文件夹使用另一个模块:shutil
-
shutil.rmtree(path)
-
os.removedirs(name) :递归删除空文件夹
-
os.rename(src, dst) :文件,目录重命名,目标不能事先存在.
import os
os.remove('a.txt')
os.rmdir('aa') # 只能删除空目录
os.removedirs('bb')
os.rename('abc','def')
-
shutil
import shutil
shutil.rmtree('aa') # 可以删除带内容目录
和路径相关的属性,更多相关的操作被封装在os.path这个模块中.
-
os.curdir :当前路径
-
os.sep :路径分隔符
-
os.altsep :备用的分隔符
-
os.extsep :扩展名分隔符
-
os.pathsep :路径分隔符
-
os.linesep :行分隔符,不要在写文件的时候,使用这个属性.
import os
print(os.curdir) # .
print(os.sep) # \
print(os.altsep) # /
print(os.extsep) # .
print(os.pathsep) # ;
-
os.path.exists(path) , 如果path存在,返回True;如果path不存在,返回False
-
os.stat('20190409_192149.mp4').st_size , 获取文件大小
-
os.path.abspath() , 获取一个文件的绝对路径
path = '20190409_192149.mp4' # D:\code\s21day14\20190409_192149.mp4
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))
-
os.path.join ,路径的拼接
import os
path = "D:\code\s21day14" # user/index/inx/fasd/
v = 'n.txt'
result = os.path.join(path,v)
print(result)
result = os.path.join(path,'n1','n2','n3')
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)
-
补充:
-
转义
v1 = r"D:\code\s21day14\n1.mp4" (推荐)
print(v1)
v2 = "D:\\code\\s21day14\\n1.mp4"
print(v2)
-
-
os.path.exists(path) :判断路径是否真正存在.
-
os.path.isabs(path) :判断是否是绝对路径
-
os.path.isfile(path) :判断是否是文件
-
os.path.isdir(path) :判断是否是目录
-
os.path.getsize(path) :获取文件的字节数.如果是文件夹,返回0或者是一个不准确的值.
# os
# 文件和文件夹相关的
# os.listdir
# os.remove
# os.rename
# os.mkdir
# os.rmdir
# os.makedirs
# os.removedirs
# 和执行操作系统命令相关
# os.popen/os.system
# import os
# os.system('dir')
# ret = os.popen('dir')
# print(ret.read())
# 工作目录:在哪个文件下执行的这个py文件,哪一个目录就是你的工作目录
# import os
# os.chdir('D:\python_22\day21')
# print('-->',os.getcwd())
# open('s21day21tmp','w').close()
# os.path
# os.path.isfile
# os.path.isdir
# os.path.isexit
# ps.path.basename 获取这个路径的最后一个值
# D:\python_22\day21 --> day21
# D:\python_22\day21\3.递归习题.py --> 3.递归习题.py
# os.path.dirname 获取这个路径的上一级目录
# D:\python_22\day21 --> D:\python_22
# D:\python_22\day21\3.递归习题.py --> D:\python_22\day21
# os.path.split(path)
# D:\python_22\day21\3.递归习题.py -->(D:\python_22\day21,3.递归习题.py)
# os.path.join(dirname,basename) 跨平台的
# os.path.getsize
# oa.path.getmtime/getatimes
# sys 和python解释器交互的
# sys.path 模块搜索路径
# sys.argv 在运行python脚本的时候写在python命令后面的是啥,打印出来的就是啥
# sys.modules 查看导入了哪些模块
# import sys
# if sys.argv[1] == 'alex' and sys.argv[2] == 'sb':
# print('登录成功')
7.2.5 sys python解释器相关的数据
-
sys.getrefcount , 获取一个值的应用计数
a = [11,22,33]
b = a
print(sys.getrefcount(a))
-
sys.getrecursionlimit , python默认支持的递归数量
-
sys.stdout.write --> print (进度)
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.path ,默认Python去导入模块时,会按照sys.path中的路径挨个查找。
# import sys
# sys.path.append('D:\\')
# import oldboy
-
sys是解释器相关的数据:递归次数/引用次数
7.2.5 hashlib 将指定的 “字符串” 进行加密
包含很多的加密算法. MD5, sha1 sha256 sha512......
用途:
-
密码加密.不能以明文的形式存储密码.密文的形式.
-
文件的校验.
用法:
-
将bytes类型字节 转化成 固定长度的16进制数字组成的字符串.
-
不同的bytes利用相同的算法(MD5)转化成的结果一定不同.
-
相同的bytes利用相同的算法(MD5)转化成的结果一定相同.
-
hashlib算法不可逆(MD5中国王晓云破解了).
import hashlib
def get_md5(data):
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("sidrsicxwersdfsaersdfsdfresdy54436jgfdsjdxff123ad".encode('utf-8'))
obj.update(data.encode('utf-8'))
result = obj.hexdigest()
return result
val = get_md5('123')
print(val)
# 动态加盐
def get_md5(data):
obj = hashlib.md5("sidrsicxwersdfsaersdfsdfresdy54436jgfdsjdxff123ad"[::2].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):
obj = hashlib.md5("12:;idrsicxwersdfsaersdfsdfresdy54436jgfdsjdxff123ad".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('登陆失败')
#文件的校验
# linux中一切皆文件: 文本文件,非文本文件,音频,视频,图片....
# 无论你下载的视频,还是软件(国外的软件),往往都会有一个md5值
import hashlib
def file_md5(path):
with open(path, mode='rb') as f1:
ret = hashlib.sha256()
while 1:
b1 = f1.read(1024)
if b1:
ret.update(b1)
else:
return ret.hexdigest()
result = file_md5('pycharm-professional-2019.1.2.exe') # 6217ce726fc8ccd48ec76e9f92d15feecd20422c30367c6dc8c222ab352a3ec6
print(result)
-
赠送:密码不显示(只能在终端运行)
import getpass
pwd = getpass.getpass('请输入密码:')
if pwd == '123':
print('输入正确')
7.2.6 json 序列化【重点】将一种数据结构转换成特殊的序列
为什么存在序列化?
数据 ----> bytes
只有字符串类型和bytes可以互换.
dict,list..... -------> str <--------> bytes
数据存储在文件中,str(bytes类型)形式存储,比如字典.
数据通过网络传输(bytes类型),str 不能还原回去.
特殊的字符串:序列化.
json序列化模块: 将一种数据结构(list,tuple,dict ....)转化成特殊的序列. 【长的像列表/字典/字符串/数字/真假】
-
不同语言都遵循的一种数据转化格式,即不同语言都使用的特殊字符串。(比如Python的一个列表[1, 2, 3]利用json转化成特殊的字符串,然后在编码成bytes发送给php的开发者,php的开发者就可以解码成特殊的字符串,然后在反解成原数组(列表): [1, 2, 3])
-
通用的序列化模块,只支持有限的类型,并且规则复杂,int,str,dict,list,float ,bool
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 :将数据转换成字符串,用于存储或网络传输.
import json
# s = json.dumps([1,2,3]) # 把指定的对象转换成json格式的字符串
# print(type(s))
# print(s) # '[1,2,3]' [1,2,3]
#
# s = json.dumps((1,2,3)) # 元组序列化后,变成列表
# print(s)
# res = json.dumps(10)
# print(res) # '10'
# res = json.dumps({'name':'Andy','age':10})
# print(res) # {"name": "Andy", "age": 10}
# res = json.dumps(set('abc')) # Object of type 'set' is not JSON serializable
# 将json结果写到文件中
# with open('a.txt',mode='at',encoding='utf-8') as f:
# json.dump([1,2,3],f)
# 反序列化
# res = json.dumps([1,2,3])
# lst = json.loads(res) # 反序列化
# print(type(lst))
# print(lst)
# 元组会变成列表
# res = json.dumps((1,2,3))
# lst = json.loads(res) # 反序列化
# print(type(lst))
# print(lst)
# 从文件中反序列化
# with open('a.txt',encoding='utf-8')as f:
# res = json.load(f)
# print(type(res))
# print(res)
# json
# json.dumps(obj)
# json.dump(obj,f)
# json.loads(s)
# json.load(f)
# json文件通常是一次性写,一次性读.
# 使用另一种方式,可以实现多次写,多次读.
# 把需要序列化的对象.通过多次序列化的方式, 用文件的write方法,把多次序列化后的json字符串
# 写到文件中.
# with open('json.txt',mode='at',encoding='utf-8') as f:
# f.write(json.dumps([1,2,3]) + '\n')
# f.write(json.dumps([4,5,5]) + '\n')
# 把分次序列化的json字符串,反序列化回来
with open('json.txt',mode='rt',encoding='utf-8') as f:
# res = json.loads(f.readline().strip())
# print(res)
# res2 = json.loads(f.readline().strip())
# print(res2)
# 使用循环改进:
for x in f:
print(json.loads(x.strip()))
"""
json:
1.不是所有的数据类型都可以序列化.结果是字符串.
2.不能多次对同一个文件序列化.
3.json数据可以跨语言
pickle:
1.所有python类型都能序列化,结果是字节串.
2.可以多次对同一个文件序列化
3.不能跨语言.
"""
+-------------------+---------------+
| Python | JSON |
+===================+===============+
| dict | object |
+-------------------+---------------+
| list, tuple | array |
+-------------------+---------------+
| str | string |
+-------------------+---------------+
| int, float | number |
+-------------------+---------------+
| True | true |
+-------------------+---------------+
| False | false |
+-------------------+---------------+
| None | null |
+-------------------+---------------+
l1 = [1, 2, 3, {'name': 'alex'}]
import json
#dump load 只能写入文件,只能写入一个数据结构
with open('json文件1',encoding='utf-8',mode='w') as f1:
json.dump(l1,f1)
#读取数据
with open('json文件1',encoding='utf-8') as f2:
l1 = json.load(f2)
print(l1,type(l1))
# 一次写入文件多个数据怎么做? dumps loads 主要用于网络传输,但是也可以读写文件。
dic1 = {'username': 'alex'}
dic2 = {'username': '太白'}
dic3 = {'username': '大壮'}
with open('json文件1',encoding='utf-8',mode='w') as f1:
f1.write(json.dumps(dic1) + '\n')
f1.write(json.dumps(dic2) + '\n')
f1.write(json.dumps(dic3) + '\n')
with open('json文件1',encoding='utf-8') as f1:
for i in f1:
print(json.loads(i))
7.2.7 pickle python语言遵循的一种数据转换格式(序列化)
1.只能是Python语言遵循的一种数据转化格式,只能在python语言中使用。
2.支持Python所有的数据类型包括实例化对象。
3 pickle python特有的序列化模块,支持几乎所有的数据类型
l1 = [1, 2, 3, {'name': 'alex'}]
# dumps loads 只能用于网络传输
# import pickle
# st = pickle.dumps(l1)
# print(st) # bytes
#
# l2 = pickle.loads(st)
# print(l2,type(l2))
# dump load 直接写入文件
# import pickle
# dic1 = {'name':'oldboy1'}
# dic2 = {'name':'oldboy2'}
# dic3 = {'name':'oldboy3'}
#
# f = open('pick多数据',mode='wb')
# pickle.dump(dic1,f)
# pickle.dump(dic2,f)
# pickle.dump(dic3,f)
# f.close()
# import pickle
# f = open('pick多数据',mode='rb')
# print(pickle.load(f))
# print(pickle.load(f))
# print(pickle.load(f))
# f.close()
import pickle
def func():
print('in func')
# f = open('pick对象',mode='wb')
# pickle.dump(func,f)
# f.close()
# f = open('pick对象', mode='rb')
# ret = pickle.load(f)
# print(ret)
# ret()
class Course:
def __init__(self,name,period,price):
self.name = name
self.period = period
self.price = price
# python = Course('python','6 moneth',21800)
# linux = Course('linux','5 moneth',19800)
# go = Course('go','4 moneth',12800)
import pickle
# with open('pickle_file','ab') as f:
# pickle.dump(linux,f)
# pickle.dump(go,f)
with open('pickle_file','rb') as f:
while True:
try:
obj = pickle.load(f)
print(obj.name,obj.period)
except EOFError:
break
7.2.8 re模块 提供和正则相关的一些方法
7.2.9 requests 提供爬虫相关的方法
7.2.10 logging 模块,提供日志相关的功能能(见博客https://www.cnblogs.com/biu-py/)
7.2.11 shutil 高级的 文件、文件夹、压缩包 处理模块
-
shutil.copy() 函数实现文件复制功能,将 source 文件复制到 destination 文件夹中,两个参数都是字符串格式。如果 destination 是一个文件名称,那么它会被用来当作复制后的文件名称,即等于 复制 + 重命名。
import shutil
shutil.copy2('D:\python_22\day21\lianjia.html',
'D:\python_22\day21\lianjia_bk.html') # 拷贝文件
-
shutil.copytree(source, destination) shutil.copytree()函数复制整个文件夹,将 source 文件夹中的所有内容复制到 destination 中,包括 source 里面的文件、子文件夹都会被复制过去。两个参数都是字符串格式。
注意,如果 destination 文件夹已经存在,该操作并返回一个 FileExistsError 错误,提示文件已存在。即表示,如果执行了该函数,程序会自动创建一个新文件夹(destination参数)并将 source 文件夹中的内容复制过去,第三个参数表示不想复制的文件
import shutil
shutil.copytree("outer",
"outer3",
ignore=shutil.ignore_patterns("__init__.py","sag"))
-
shutil.move(source, destination) shutil.move() 函数会将 source 文件或文件夹移动destination 中。返回值是移动后文件的绝对路径字符串。 如果 destination 指向一个文件夹,那么 source 文件将被移动到 destination 中,并且保持其原有名字
import shutil
shutil.move("D:\python_22\day21\day20_bak","D:\python_22\day20", copy_function=shutil.copy2)
# 删除目录
import shutil
shutil.rmtree(path)
# 查看当前磁盘的使用情况
total, used, free = shutil.disk_usage("c:\\")
print("当前磁盘共: %iGB, 已使用: %iGB, 剩余: %iGB"%(total / 1073741824, used / 1073741824, free / 1073741824))
shutil.make_archive('outer_z', 'zip','D:\python_22\day21\outer') # 压缩文件
shutil.unpack_archive('outer_z.zip',r'D:\python_22\day21\unzip') # 解压文件
7.3 项目结构
设计项目目录结构的作用
-
可读性高: 不熟悉这个项目的代码的人,一眼就能看懂目录结构,知道程序启动脚本是哪个,测试目录在哪儿,配置文件在哪儿等等。从而非常快速的了解这个项目。
-
可维护性高: 定义好组织规则后,维护者就能很明确地知道,新增的哪个文件和代码应该放在什么目录之下。这个好处是,随着时间的推移,代码/配置的规模增加,项目结构不会混乱,仍然能够组织良好。
较好的目录结构方式(推荐)
bin是一个存放启动文件的目录,不管你文件的名字叫什么你只要放到bin目录下大家就知道这是一个启动文件
cores是一个存放项目的主逻辑,比如购物车,里边写的就是登陆充值购买等功能
lib是存放有一个公共组件的目录,什么是公共组件,就是在这个项目中陪别的功能频繁使用的功能
conf 是一个存放配置文件的目录,配置文件就是文件中的一些全局变量移到这里
db是存放这个项目需要使用到的一些文件
log是这个项目需要记录的日志文件存放位置
具体分析:
#===============>start.py
# 开启项目的start文件。
import sys,os
BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
from core import src
if __name__ == '__main__':
src.run()
#===============>settings.py
# 配置文件,放一些路径或者信息等配置
import os
BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DB_PATH=os.path.join(BASE_DIR,'db','db.json')
LOG_PATH=os.path.join(BASE_DIR,'log','access.log')
LOGIN_TIMEOUT=5
"""
logging配置
"""
# 定义三种日志输出格式
standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
'[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字
simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s'
# log配置字典
LOGGING_DIC = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': standard_format
},
'simple': {
'format': simple_format
},
},
'filters': {},
'handlers': {
#打印到终端的日志
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler', # 打印到屏幕
'formatter': 'simple'
},
#打印到文件的日志,收集info及以上的日志
'default': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件
'formatter': 'standard',
'filename': LOG_PATH, # 日志文件
'maxBytes': 1024*1024*5, # 日志大小 5M
'backupCount': 5,
'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了
},
},
'loggers': {
#logging.getLogger(__name__)拿到的logger配置
'': {
'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG',
'propagate': True, # 向上(更高level的logger)传递
},
},
}
#===============>src.py
# 主要逻辑部分:
# 核心逻辑,代码放在这。
from conf import settings
from lib import common
import time
logger=common.get_logger(__name__)
current_user={'user':None,'login_time':None,'timeout':int(settings.LOGIN_TIMEOUT)}
def auth(func):
def wrapper(*args,**kwargs):
if 