Python全栈开发之7、模块和几种常见模块以及format知识补充
一、模块的分类
Python流行的一个原因就是因为它的第三方模块数量巨大,我们编写代码不必从零开始重新造轮子,许多要用的功能都已经写好封装成库了,我们只要直接调用即可,模块分为内建模块、自定义的模块、安装的第三方的模块,一般都放在不同的地方,下面来看一下内建模块怎么导入,以及他们存放的位置。
import sys # 可以用import 直接导入内建模块 for i in sys.path: # sys.path存放有每次导入模块都会去搜寻的路径 print(i) ''' C:\Users\Tab\AppData\Local\Programs\Python\Python35\python.exe C:/Users/Tab/PycharmProjects/modules/1.py C:\Users\Tab\PycharmProjects\modules C:\Users\Tab\PycharmProjects\modules #自定义模块放在当前工作空间 C:\Users\Tab\AppData\Local\Programs\Python\Python35\python35.zip C:\Users\Tab\AppData\Local\Programs\Python\Python35\DLLs C:\Users\Tab\AppData\Local\Programs\Python\Python35\lib #内建模块存放位置 C:\Users\Tab\AppData\Local\Programs\Python\Python35 C:\Users\Tab\AppData\Local\Programs\Python\Python35\lib\site-packages #第三方库的安装位置 ''' #可以向sys.path中用append()的方法导入,例如 sys.path.append('D:')后,在D:目录下的py文件可以用import直接导入 print(sys.platform) # win32 sys.platform可以获取当前工作平台(win32)or linux #此外 sys.argv可以获取脚本的参数,argv[0] 是脚本名,argv[1]是第一个参数...
二、模块的导入
首先要说明下,自己定义的模块的名字和内建模块的名字不要相同,否则的话,导入的时候会出现问题,内建的模块,和第三方模块已经存在sys.path的路径中,所以直接导入即可,下面来说明下自己写了一个项目,项目中的各个库是如何导入的,假设我定义了一个modules的项目,下面是其目录结构看如何在1.py文件导入
上图左边是目录树,右边是在1.py文件中如何导入在lib/account.py下定义的函数,列举了三种常用导入方式。
三、os模块
os模块是与操作系统相关的模块,比如说对文件和目录的操作,获取路径等,都可以用os模块来实现 ,os模块提供的功能太多,下面来简单的看一下常用用法
import os print(os.getcwd()) # C:\Users\Tab\PycharmProjects\modules 获取当前工作路径 print(os.environ) # 获取系统环境变量 print(os.getenv('PATH')) # 获取PATH环境变量的值 os.mkdir('test') # 在当前工作空间创建一个test目录 os.remove('path/to/file') # 删除文件 os.rmdir('test') #删除'test'目录 print(os.stat('1.py')) # 返回文件的详细信息 os.stat_result(st_mode=33206 ... st_nlink=1, st_uid=0, st_gid=0, st_size=3152...) print(os.path.basename(r'C:\Users\Tab\PycharmProjects\modules\1.py')) #获取路径下的文件名 1.py print(os.path.abspath('1.py')) #获取文件的绝对路径 C:\Users\Tab\PycharmProjects\modules\1.py print(os.path.dirname(r'C:\Users\Tab\PycharmProjects\modules\1.py')) #获取路径下的路径名 print(os.path.split(r'C:\Users\Tab\PycharmProjects\modules\1.py')) #分割文件和路径 print(os.path.join(r'C:\Users\Tab\PycharmProjects\modules','1.py')) #合并路径
四、hashlib模块
hashlib是一个加密模块,提供了常见的加密算法,比如MD5,SHA1,SHA256等,它通过一个函数,把任意长度的数据转换为一个长度固定的数据串,常用来保存密码等,比如将用户的密码用MD5加密后,保存到数据库,用户登录时先计算用户输入的明文口令的MD5,然后和数据库存储的MD5对比,如果一致,说明密码输入正确,如果不一致,密码肯定错误。下面来看一下用法
import hashlib passwd=hashlib.sha256() passwd.update(bytes('123456',encoding='utf-8')) # 假设密码是123456 将其转换为字节,传入函数 print(passwd.hexdigest()) # 8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92 passwd=hashlib.sha256(bytes('wxtrkbc',encoding='utf-8')) #对原始密码加一个复杂字符串来提高安全性,俗称“加盐”: passwd.update(bytes('123456',encoding='utf-8')) print(passwd.hexdigest()) # d2641b3d7243c87fe3f1312a30fe9909ae80d034f0a799da0897934311ee351b
五、datetime模块
datetime是一个与时间相关的模块,可以处理日期和时间的互换,下面来看一下用法
import datetime print(datetime.datetime.now()) # 2016-05-17 15:46:40.784376 获取当前的日期和时间 print(datetime.datetime.now()+datetime.timedelta(days=10)) # 2016-05-27 15:47:45.702528 将当前的时间向后推迟10天 print(datetime.date.today()) # 2016-05-17 获取当前的日期 print(datetime.datetime.utcnow()) # 2016-05-17 08:23:41.150628 获取格林威治时间 print(datetime.datetime.now().timetuple()) # time.struct_time(tm_year=2016 ... tm_hour=16,...)获取当前一个包含当前时间的结构体 print(datetime.datetime.now().timestamp()) # 1463473711.057878 获取当前的时间戳 print((datetime.datetime.fromtimestamp(1463473711.057878))) # 2016-05-17 16:28:31.057878 将时间戳转换成日期和时间 print(datetime.datetime.strptime('2016-05-17 16:28:31','%Y-%m-%d %H:%M:%S')) #2016-05-17 16:28:31 str转换为datetime print(datetime.datetime.now().strftime('%D, %m %d %H:%M')) #05/23/16, 05 23 10:10 datetime转换为str
六、Json
如果要在不同的平台间传递信息的话,就可以用到Json模块,比如说,我们要和前端交互的话,数据之间的传递就可以用Json,Json是一种标准格式,能被所有的语言处理。下面来简单的看一下常用的用法,主要是Python常用数据结构比如dict和list与字符串之间的转换,但是tuple不能,tuple是Python里面特有的,而其他语言没有,再者,Json的loads和dumps方法不太常用。
import json s='{"name":"jason","age":18}' # 外面不能为双引号 l='[1,2,3,4]' print(json.loads(s)) # 字符串转字典的时候,字符串里面不能为单引号,否则报错 {'name': 'jason', 'age': 18} print(json.loads(l),type(json.loads(l))) # 字符串转列表 [1, 2, 3, 4] <class 'list'> user_list=['alex','jason'] print(type(json.dumps(user_list)),json.dumps(user_list)) #列表转字符串 <class 'str'> ["alex", "jason"] dic = {'k1':1,'k2':2} json.dump(dic,open('db','w')) # 将字典序列化导入文件 r=json.load(open('db','r')) # 反序列化从文件中导处 print(r,type(r)) # {'k1': 1, 'k2': 2} <class 'dict'>
七、XMl模块
XML也是一种可以实现不同语言之间交换的可扩展标记语言,XMl比Json复杂,虽然没有Json流行,但是在许多场合下也经常用到,所以有必要了解一下,假设我有一个下面这样的XML文件,文件名为1.xml,然后以这个文件我们来对其进行操作
<data> <country name="Liechtenstein"> <rank updated="yes">2</rank> <year>2023</year> <gdppc>141100</gdppc> <neighbor direction="E" name="Austria" /> <neighbor direction="W" name="Switzerland" /> </country> <country name="Singapore"> <rank updated="yes">5</rank> <year>2026</year> <gdppc>59900</gdppc> <neighbor direction="N" name="Malaysia" /> </country> <country name="Panama"> <rank updated="yes">69</rank> <year>2026</year> <gdppc>13600</gdppc> <neighbor direction="W" name="Costa Rica" /> <neighbor direction="E" name="Colombia" /> </country> </data>
下面我们来用Python来解析一下这个文件,具体的代码看下面
from xml.etree import ElementTree as ET #利用ElementTree.XML将字符串解析成xml对象 node=ET.XML(open('1.xml','r',encoding='utf-8').read()) # 从1.XMl文件中读取内容为字符串,然后用XML解析为一个XML结构体 print(node) # node为根节点 <Element 'data' at 0x000001EFD15C33B8> for node1 in node: # 获取下一节点 country print(node1.attrib) # 打印country节点的属性 name for node2 in node1: # 获取 country下面的所有节点,以及节点的内容 print(node2.tag,node2.text) # 利用ElementTree.parse将文件直接解析成xml对象 tree=ET.parse('1.xml') # 解析成xml对象 root=tree.getroot() # 获取根节点 <Element 'data' at 0x00000202AA8F33B8> for node in root.iter('year'): # 跳过country节点直接获取所有的year节点 print(node.tag,node.text) # 打印year标签和内容 year 2023 node.set('name', 'jason') # 修改year的属性,增加一个name=jsaon的属性 node.set('age', '18') del node.attrib['age'] # 删除节点属性 node.text='1984' # 修改year的内容为1984 k=root.find('country') # 找到country k1=root.find('country').find('rank') # find要一级级的找,找到第一个country下的rank k.remove(k1) # 删除第一个country下的rank节点 tree.write('1.xml') # 修改完成后只有写入文件中才算有效
八、logging
logging,是用来纪录日志的模块,可以自动帮我们纪录程序运行中出现的错误,出了问题可以方便我们后来去日志中查找原因,在实际开发中非常好用,下面来简单的看一下用法。
import logging logging.basicConfig(filename='log.log', # 事件记录的文件名 format='%(asctime)s-%(name)s-%(levelname)s-%(module)s: %(message)s', #事件纪录格式 datefmt='%Y-%m-%d %H:%M:%S %p', # 时间格式 level=10,) logging.error('error') # 2016-05-25 19:46:39 PM-root-ERROR-url: error # 同时写到多个文件的方式 file_1=logging.FileHandler('1.log','a') fmt=logging.Formatter(fmt='%(asctime)s-%(name)s-%(levelname)s-%(module)s: %(message)s',datefmt='%Y-%m-%d %H:%M:%S %p') file_1.setFormatter(fmt) file_2=logging.FileHandler('2.log','a') fmt=logging.Formatter() file_2.setFormatter(fmt) log=logging.Logger('1',level=logging.ERROR) log.addHandler(file_1) log.addHandler(file_2) # 2016-05-28 22:16:40 PM-1-CRITICAL-url: 33333 (1.log) # 33333 (2.log) log.critical('33333')
九、 format
以前我们都是用百分号格式化字符串,现在我们用一种更牛逼的方式来格式化字符串format,下面来看一下format的常规用法。
print("1 am {},age {}".format('jason',18)) # 用{}当作占位符 print("1 am {},age {}".format(*['jason',18])) # 用*传递一个列表进去 print("1 am {0},age {1},score{1}".format('jason',18)) # 1 am jason,age 18,score18 用 0,1等数字来应用 print("1 am {name},age {age}".format(name='jason',age=18)) # 用key引用,传递键值对 print("1 am {name},age {age}".format(**{'name':'jason','age':18})) # 用**传递一个字典 print("1 am {0[0]},age {1[1]}".format([1,2,3],[4,5,6])) # 1 am 1,age 5 print("i am {:s}, age {:d}".format(*["jason", 18])) # 还可用指定整形 print("i am {:.2%}".format(0.2)) # i am 20.00%
十、练习
1、写一个用户的登陆注册的界面,用户的密码用hashlib加密存在文件中,登陆时候,用户的密码要和文件中的密码一致才行
def sha(password): #加密函数 passwd = hashlib.sha256(bytes('wxtrkbc', encoding='utf-8')) passwd.update(bytes(password,encoding='utf-8')) return passwd.hexdigest() def register(user,passwd): #注册函数,并将密码加密后存在文件中 with open('db','a') as f : f.write(user+':'+sha(passwd)) def login(user,passwd): #登陆函数 并判断登陆密码是否正确 with open('db','r',encoding='utf-8')as f : for line in f : info=line.strip().split(':') if user==info[0] and sha(passwd)==info[1]: # 将密码加密后与文件中存储的进行对比,一样就是相同的用户 print('login success') return True else: print('login error') return False def main(): k=input('1注册,2登陆') if int(k)==1: user=input('输入用户名:') passwd=input('输入密码:') register(user,passwd) elif int(k)==2: user = input('输入用户名:') passwd = input('输入密码:') login(user,passwd) else: return
2、写一个进度条,用百分比显示进度
import os,sys,time for i in range(101): sys.stdout.write('\r%s %s%%' % ('#'*int(i/100*100),int(i/100*100))) sys.stdout.flush() # s+='#' # print('%s %s%%' %(s,int(i/50*100))) time.sleep(0.2) # for i in range(101): #改进一下 # #显示进度条百分比 #号从1开始 空格从99递减 # hashes = '#' * int(i / 100.0 * 100) # spaces = ' ' * (100 - len(hashes)) # sys.stdout.write("\r[%s] %d%%" % (hashes + spaces, i)) # sys.stdout.flush() # time.sleep(0.05)
3、利用微信接口来判断某一QQ号的状态
import requests from xml.etree import ElementTree as ET response = requests.get('http://www.webxml.com.cn//webservices/qqOnlineWebService.asmx/qqCheckOnline?qqCode=5768476386') r = response.text node = ET.XML(r) if node.text == 'Y': print('在线') elif node.text == 'V': print('隐身') else: print('离线')
4、利用微信接口来获取列车时刻表
import requests from xml.etree import ElementTree as ET response=requests.get('http://www.webxml.com.cn/WebServices/TrainTimeWebService.asmx/getDetailInfoByTrainCode?TrainCode=K234&UserID=') r=response.text root=ET.XML(r) for node in root.iter('TrainDetailInfo'): print(node.find('TrainStation').text,node.find('ArriveTime').text)