python编程 基础入门学习笔记五

本节内容

 主要介绍下常用模块

1.模块的介绍

2.time,datetime

3.random

4.os,sys,shutil

5.json,pickle

6.shelve

7.xml处理

8.yaml处理

9.configparse

10.hashlib

11.re正则表达式

12.subprocess

13.logging

14.练习

 

1.模块的介绍                                                                                                                                                              

1)定义:

模块,用来从逻辑上组织python代码(变量,函数,类,逻辑:实现一个功能),本质就是.py结尾的python文件(举个例子,文件名:test.py,对应的模块名:test)。

包,用来从逻辑上组织模块的,本质就是一个目录(必须带一个__init_.py文件)

2)导入方法:

import module_name   #导入一个模块

import module1_name,module2_name   #导入多个模块

from module_name import *  #导入一个模块的全部代码,一般不建议使用

from module_name import func1,func2,m1,m2  #导入一个模块的多个函数或变量

from module_name import logger as logger_R#多个模块有相同函数或文件名时使用

3)import 本质(路径搜索和搜索路径)

导入模块的本质就是把python文件解释一遍

(import test    #test='test.py all code')

(from test import m1    #m1='code')

import module_name----->module_name.py---->module_name.py的路径---->sys.path

导入包的本质就是执行该包下的__init__.py文件

4)导入优化

from module_name import func

from module_name import func as other_name

5)模块的分类

 标准库

 开源模块

 自定义模块

2.time,datetime                                                                                                                                                       

time 

在python中,通常有几种方式来表示时间:1)时间戳;2)格式化的时间字符串;3)元组(struct_time)共九个元素。

>>> import time
>>> time.time()    #以时间戳的形式显示当前时间
1499318673.700064
>>> x=time.time()
>>> x
1499318691.528084
>>> x/3600/24/365    #将时间戳换算为年,一小时3600秒,一天24小时,一年365天
47.543083825725645
>>> 1970+47    #由于Unix系统是1970年发明的,所以起点时间从1970年算去,如此推算正好2017年
2017
时间戳
>>> '13:40:57 2017' #类似于这种方式,就成为格式化的时间字符串
'13:40:57 2017'
格式化的时间字符串
>>> import time
>>> time.localtime()
time.struct_time(tm_year=2017, tm_mon=7, tm_mday=6, tm_hour=13, tm_min=29, tm_sec=47, tm_wday=3, tm_yday=187, tm_isdst=0)

#tm_isdst 是夏令时;utc是世界协调时间,一个球体360°按照每15°划分一个区,共划分为24个时区,中国属于东8区(UTC+8)
元组(struct_time)

time模块中的变量、函数,大家在使用的时候,如果忘了,可以使用 >>>help(time) 来查看

>>> import time
>>> time.timezone    #获取时区的时间戳
-28800
>>> 28800/3600    #换算成小时,中国北京处于东8区
8.0
>>> time.altzone    #获取夏令时的时间戳
-32400
>>> time.daylight    #是否使用了夏令时,0为没有使用    
0
Variables
>>> time.time()    #获取当前时间的时间戳
1499320021.678164
>>> time.sleep(2)    #睡2秒
>>> time.gmtime()    #把时间戳转换成UTC时区的元组
time.struct_time(tm_year=2017, tm_mon=7, tm_mday=6, tm_hour=5, tm_min=50, tm_sec=42, tm_wday=3, tm_yday=187, tm_isdst=0)
>>> time.localtime()    #把时间戳转换成本地时区(在中国就是UTC+8时区)的元组
time.struct_time(tm_year=2017, tm_mon=7, tm_mday=6, tm_hour=13, tm_min=51, tm_sec=55, tm_wday=3, tm_yday=187, tm_isdst=0)
>>> x=time.localtime()
>>> x.tm_year    #取年
2017
>>> x.tm_mon    #取月
7
>>> x=time.localtime(1111111111)    #已知时间戳,可以得知是哪一年的哪一天
>>> print("This is %d's %d" %(x.tm_year,x.tm_yday))
This is 2005's 77
>>> x
time.struct_time(tm_year=2005, tm_mon=3, tm_mday=18, tm_hour=9, tm_min=58, tm_sec=31, tm_wday=4, tm_yday=77, tm_isdst=0)
>>> time.mktime(x)    #将元组转换为时间戳,与localtime整好反过来
1111111111.0
>>> time.strftime("%Y-%m-%d %H:%M:%S",x)  #x是元组,转换成格式化的时间字符串
'2005-03-18 09:58:31'
>>> time.strptime('2005-03-18 09:58:31',"%Y-%m-%d %H:%M:%S")    #将格式化的时间字符串按照给定的格式(必须一一对应)转换为元组
time.struct_time(tm_year=2005, tm_mon=3, tm_mday=18, tm_hour=9, tm_min=58, tm_sec=31, tm_wday=4, tm_yday=77, tm_isdst=-1)
>>> time.asctime(x)    #把元组转换为格式化的时间字符串
'Fri Mar 18 09:58:31 2005'
>>> time.asctime()    #当没有传值的时候,默认把当前时间的元组转换为格式化的时间字符串
'Thu Jul  6 14:24:01 2017'
>>> time.ctime(1111111111)    #已知时间戳,把时间戳转换为格式化的时间字符串
'Fri Mar 18 09:58:31 2005'
>>> time.ctime()    #当没有传值的时候,默认把当前时间的时间戳转换为格式化的时间字符串
'Thu Jul  6 14:26:57 2017'
Functions

datetime

年月日分时秒的相关获取

>>> import datetime
>>> datetime.datetime.now()    #获取当前日期
datetime.datetime(2017, 7, 6, 14, 30, 13, 60383)
>>> datetime.datetime.now()+datetime.timedelta(3)    #获取三天后的时间
datetime.datetime(2017, 7, 9, 14, 31, 53, 932152)
>>> datetime.datetime.now()+datetime.timedelta(-3)    #获取三天前的时间
datetime.datetime(2017, 7, 3, 14, 32, 35, 710542)
>>> datetime.datetime.now()+datetime.timedelta(hours=-3)    #获取三小时前的时间
datetime.datetime(2017, 7, 6, 11, 33, 16, 784891

datetime.timedelta()模块不能单独使用,必须结合datetime.datetime.now()才能操作,具体操作可以 >>>help(datetime) 来查看。

3.random                                                                                                                                                                 

 random模块,主要用来取随机数。

>>> import random
>>> random.random()    #随机取0到1之间的浮点数
0.3842743626718087
>>> random.uniform(1,3)    #指定范围随机取1到3之间的浮点数
3.6570295738638694
>>> random.randint(1,3)    #指定范围随机取1到3之间的整数
3
>>> random.randrange(3)    #指定范围随机取range(3)里的整数,不包括3
2
>>> random.choice('hello')    #随机取任一字符
'o'
>>> random.choice([1,4,6])    #随机取任一列表/元组中的元素
1
>>> random.sample('hello',2)    #随机取字符串中的任2个字符
['o', 'h']
>>> item=[1,2,3,4,5,6,7,8]    #已知item是个有序列表
>>> random.shuffle(item)    #通过shuffle可以实现打乱顺序,也就是洗牌功能
>>> item
[5, 8, 7, 1, 3, 4, 2, 6]

举个6位简单随机验证码的例子,

#-*- coding:utf-8 -*-

#随机验证码

import random

checkcode=''
for i in range(6):
    current=random.randint(0,6)
    if current==i:
        code=chr(random.randint(65,90))#随机获取大写字母
    else:
        code=str(random.randint(0,9))
    checkcode+=code
print(checkcode)
View Code

不难吧?多练习,就方便日后实际应用了。

4.os,sys,shutil                                                                                                                                                        

 os

 os模块是对操作系统的一些调用,模拟对操作系统的一系统指令。

>>> import os
>>> os.getcwd()    #获取当前目录的操作路径
'D:\\Python34'
>>> os.chdir("C:\\Users")     #修改当前路径到C:\Users
>>> os.getcwd()
'C:\\Users'
>>> os.chdir(r'D:\Python34')     #修改当前路径到D:\Python34,这种方式比较推荐使用
>>> os.getcwd()
'D:\\Python34'
>>> os.curdir    #os的一个属性值,返回值为当前目录的字符串名
'.'
>>> os.pardir    #os的一个属性值,返回值为当前目录的父目录字符串名
'..'
>>> os.makedirs(r'd:\Python34\a\b\c')    #递归的创建多层目录,即使a,b不存在
>>> os.removedirs(r'd:\Python34\a\b\c')    #删除多层空目录,如目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依次类推
>>> os.rmdir(r'd:\Python34\a\b\c')    #删除单级空目录,若目录不为空则无法删除,报错;相当于shell中的rmdir dirname
>>> os.listdir(os.curdir)    #列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表形式打印
['a', 'DLLs', 'Doc', 'filelist_bak.txt', 'file_test', 'include', 'Lib', 'libs', 'LICENSE.txt', 'NEWS.txt', 'pip-7.1.2', 'python.exe', 'pythonw.exe', 'README.txt', 'Scripts', 'setuptools-18.2', 'shellsed.py', 'Source', 'tcl', 'test.txt', 'Tools', '安装说明.txt']
>>> os.rename(r'd:\Python34\a\b',r'd:\Python34\a\c')    #重命名文件/目录
>>> os.stat('test.txt')    #获取文件/目录的状态信息
os.stat_result(st_mode=33206, st_ino=844424930249768, st_dev=3064210701, st_nlink=1, st_uid=0, st_gid=0, st_size=79, st_atime=1498110254, st_mtime=1498110254, st_ctime=1498109630)
>>> os.sep    #输出操作系统的路径分隔符,这里是win
'\\'
>>> os.linesep    #输出操作系统的行终止符,这里是win
'\r\n'
>>> os.pathsep    #输出操作系统的路径之间的分隔符,这里是win
';'
>>> os.name    #输出当前使用的操作系统类型,win->'nt';Linux->'posix'
'nt'
>>> os.system('ipconfig /all')    #运行shell命令,直接显示
>>> os.path.abspath('test.txt')    #返回path规范化的绝对路径
'D:\\Python34\\test.txt'
>>> os.path.split('D:\\Python34\\test.txt')    #将path分割成目录和文件名的二元组
('D:\\Python34', 'test.txt')
>>> os.path.dirname('D:\\Python34\\test.txt')    #返回path的目录,文件所在的目录
'D:\\Python34'
>>> os.path.basename('D:\\Python34\\test.txt')    #返回path最后的文件名,如果path以/或\结尾,则会返回空值
'test.txt'
>>> os.path.exists('D:\\Python34\\test.txt')    #判断path是否存在,灿在返回真
True
>>> os.path.isabs('D:\\Python34\\test.txt')    #是否为绝对路径
True
>>> os.path.isabs('test.txt')
False
>>> os.path.isfile('D:\\Python34\\test.txt')    #是否为文件
True
>>> os.path.isfile('D:\\Python34')
False
>>> os.path.isdir('D:\\Python34\\test.txt')    #是否为目录
False
>>> os.path.isdir('D:\\Python34')
True
>>> os.path.getatime('D:\\Python34\\test.txt')    #文件\目录最后存取时间戳
1498110254.8108337
>>> os.path.getmtime('D:\\Python34\\test.txt')    #文件\目录最后修改时间戳
1498110254.8108337
>>> os.path.getctime('D:\\Python34\\test.txt')    #文件\目录创建时间戳
1498109630.7981422
>>> os.path.join('D:\\Python34','a','c','a.txt')    #将多个路径组合后输出
'D:\\Python34\\a\\c\\a.txt'
os模块

sys

 sys.argv,获取向脚本文件传入的参数,返回列表,列表里的第一个元素是脚本文件路径和名称,后面的元素是传入的向脚本传入的参数

import sys
a=sys.argv  #获取脚本传入的参数,命令行参数list,第一个元素是程序本身路径
print(a)
#注意,在pycharm的Terminal模式下调试
sys.argv

sys.path,获取各种路径,返回列表

import
p=sys.path
print(p)
sys.path

举个“为python解释器添加新路径”的例子,

#-*- coding:utf-8 -*-
#Author:'Yang'

import sys,os

print(sys.path)    #打印python的各种路径
print(os.path.abspath(__file__))    #获取当前运行.py文件的绝对路径
print(os.path.dirname(os.path.abspath(__file__)))    #获取当前运行.py文件的父目录路径
print(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))     #获取当前运行.py文件的父目录的上一级目录路径

x=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(x)     #将获取到当前运行.py文件的父目录的上一级目录路径添加到python解释器的关联路径中
View Code

sys.exit(),退出程序

#-*- coding:utf-8 -*-
#Author:'Yang'

import sys

a=input("退出请按q:>>")
if a=='q':
    sys.exit("退出程序!")
sys.exit()

与不导入sys模块就可以直接使用的 exit()实现的功能相同

sys.version,获取python解释器的版本信息

>>> sys.version
'3.4.2 (v3.4.2:ab2c023a9432, Oct  6 2014, 22:15:05) [MSC v.1600 32 bit (Intel)]'
sys.version

sys.platform,返回操作系统平台名称,可以判断当前是什么系统

>>> sys.platform
'win32'
sys.platform

sys.stdout.wirte(),向显示器打印输出内容,循环打印不会换行,举个进度条的例子,

#-*- coding:utf-8 -*-
#Author:'Yang'

import sys,time

for i in range(50):
    sys.stdout.write("#")
    sys.stdout.flush()#强制刷新,写一行刷一行
    time.sleep(0.1)
进度条

sys.stdin.readline(),输入内容

import sys
a=sys.stdin.readline()[:-1]
print(a)
sys.stdin.readline()

例如,输入“游戏开始”,则print语句就会输出字符串“游戏开始”

shutil

 shutil是高级的文件拷贝、压缩 模块。

import shutil
f1=open("本节笔记")
f2=open("笔记2",'w')
shutil.copyfileobj(f1,f2) #拷贝文件,但是需要先打开文件才能进行拷贝
shutil.copyfileobj()
import shutil
shutil.copyfile("笔记2","笔记3")    #输入文件名就可以拷贝了,不用打开文件再拷贝
shutil.copyfile()
import shutil
shutil.copymode("本节笔记","笔记3")#仅拷贝权限。内容、组、用户均不变,在Linux比较容易查看
shutil.copymode()
import shutil
shutil.copystat("本节笔记","笔记3")    #拷贝所有的状态信息,更多时候是在Linux中使用
shutil.copystat()
import shutil
shutil.copytree("folder","new_folder")    #递归的拷贝目录下所有文件包括文件夹
shutil.rmtree("new_folder")    #递归的删除目录
shutil.move("folder","new_folder")    #递归的去移动文件,在同一个目录下移动时,相当于重命名
shutil递归用法
import shutil

shutil.make_archive("shutil_arv",'zip','E:\test\demo') #压缩
shutil.make_archive()

shutil对压缩包的处理其实是调用ZipFile和TarFile两个模块来进行的,下面用代码演示一下这两个模块的用法

#单独一个个压缩文件
import zipfile

z=zipfile.ZipFile("shutil_arv.zip","w")
z.write("p_test.py")
print("做点别的事情")
z.write("本节笔记")
z.close()

#解压
z=zipfile.ZipFile("shutil_arv.zip","r")
z.extractall()#可以设置解压路径
z.close()

import tarfile
#压缩,单独一个个压缩文件
tar=tarfile.open("shutil_arv.tar",'w')
tar.add("p_test.py")
print("做点别的事情")
tar.add("本节笔记")
tar.close()

#解压
tar=tarfile.open("shutil_arv.tar",'r')
tar.extractall(r"C:\Users\Yang\PycharmProjects\s14") #默认空时,即为当前路径
tar.close()
ZipFile和TarFile

 

5.json,pickle                                                                                                                                                            

 参考 http://www.cnblogs.com/vicky777/articles/7054119.html   “5.json和pickle序列化”,此处不赘述。

6.shelve                                                                                                                                                                   

 shelve模块是对pickle更上一层的封装,是一个简单的k,v,将内存数据通过文件持久化模块,可以持久化任何pickle可支持的python数据格式

#-*- coding:utf-8 -*-
#Author:'Yang'

import shelve
import datetime

#shelve的写功能
d=shelve.open("shelve_test")    #打开一个文件

info={'age':18,'job':'teacher'}

name=["Rose","Jack","test"]
d["name"]=name    #持久化列表
d["info"]=info    #持久化字典

d["data"]=datetime.datetime.now()    #持久化字符串

d.close()
shelve的写功能

执行代码后,目录下会生成“shelve_test.bak”,“shelve_test.data”,“shelve_test.dir”三个持久化文件,要想读出数据,只需要使用shelve的读功能就可以得到输出

#-*- coding:utf-8 -*-
#Author:'Yang'

#shelve的读功能

import shelve
import datetime

d=shelve.open("shelve_test")    #打开一个文件

name=d.get("name")
info=d.get("info")
data=d.get("data")

print(name)
print(info)
print(data)
shelve的读功能

shelve模块的使用比较简单,但是很常用。

7.xml处理                                                                                                                                                                 

 xml处理模块是实现不同语言或程序之间进行数据交换的协议,跟json模块类似,但json模块使用起来更简单,早在json还没诞生的时候,那时都选用xml,所以至今很多公司如金融行业的很多系统的接口还主要是xml。

xml的格式如下,

<?xml version="1.0"?>
<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>
test.xml

那么,通过python如何看xml的信息呢?

#-*- coding:utf-8 -*-
#Author:'Yang'

import xml.etree.ElementTree as ET

tree=ET.parse("test.xml")
root=tree.getroot()
print(root)     #打印内存地址
print(root.tag)     #打印标签名

print("分割线".center(50,"*"))

#遍历xml文档所有内容
for child in root:
    print(child.tag,child.attrib)   #取标签名,取属性值
    for i in child:
        print(i.tag,i.text,i.attrib)    #取标签名及标签值,取属性值

print("分割线".center(50,"*"))

#只遍历year节点
for node in root.iter('year'):
    print(node.tag,node.text)
View Code

看完这段代码是不是觉得xml也没那么复杂,其实就和字典操作类似。

能够查看xml了,那么通过python的xml处理模块,能否实现xml的增删改呢?

#-*- coding:utf-8 -*-
#Author:'Yang'

import xml.etree.ElementTree as ET

new_xml=ET.Element("personinfolist")  #根节点,节点名是personinfolist
personinfo=ET.SubElement(new_xml,"personinfo",attrib={"enrolled":"yes"})    #创建new_xml的子节点,子节点名是personinfo
name=ET.SubElement(personinfo,"name")
name.text="Rose"
age=ET.SubElement(personinfo,"age",attrib={"checked":"no"})   #创建personinfo的子节点,子节点名是age
sex=ET.SubElement(personinfo,"sex")   #创建personinfo的子节点,子节点名是sex
age.text='18'
sex.text='Female'

personinfo2=ET.SubElement(new_xml,"personinfo",attrib={"enrolled":"no"})    #创建new_xml的子节点,子节点名是personinfo
name=ET.SubElement(personinfo2,"name")
name.text="Jack"
age=ET.SubElement(personinfo2,"age",attrib={"checked":"no"})   #创建personinfo2的子节点,子节点名是age
sex=ET.SubElement(personinfo2,"sex")   #创建personinfo2的子节点,子节点名是sex
age.text='20'
sex.text='Male'

et=ET.ElementTree(new_xml)  #生成文档对象
et.write("personinfo.xml",encoding='utf-8',xml_declaration=True)   #写入

ET.dump(new_xml)    #打印生成的格式
xml创建
#-*- coding:utf-8 -*-
#Author:'Yang'

import xml.etree.ElementTree as ET

tree=ET.parse("test.xml")
root=tree.getroot()

#修改
for node in root.iter('year'):
    print("修改前:",node.tag,node.text)
    new_year=int(node.text)+1
    node.text=str(new_year)
    node.set("updated","yes")

tree.write("test2.xml")

for new_node in root.iter('year'):
    print("修改后:", new_node.tag, new_node.text)
xml修改
#-*- coding:utf-8 -*-
#Author:'Yang'

import xml.etree.ElementTree as ET

tree=ET.parse("test.xml")
root=tree.getroot()

#删除node
for country in root.findall('country'):
    rank=int(country.find('rank').text)
    print(rank)
    if rank>50:
        root.remove(country)
tree.write("test3.xml")
xml节点删除

至此,python的xml处理模块就大概介绍这么多。

8.yalm处理                                                                                                                                                               

YALM是用来写配置文档的,python也可以很容易得处理yalm文档格式,只不过需要安装一个模块,参考文档:http://pyyaml.org/wiki/PyYAMLDocumentation

9.configparser                                                                                                                                                        

在python3.x中是configparser,在python2.中是ConfigParser,用于生成和修改常见配置文档。

#-*- coding:utf-8 -*-
#Author:'Yang'

import configparser

config=configparser.ConfigParser()

#创建
#创建的第一个节点是DEFAULT
config["DEFAULT"]={'ServerAliveInterval':'45',
                   'Compression':'yes',
                   'CompressionLevel':'9'}    #子节点

#创建的第二个节点是bitbucket.org
config['bitbucket.org']={}
config['bitbucket.org']['User']='hg'    #子节点User

#创建的第三个节点是topsecret.server.com
config['topsecret.server.com']={}
topsecret=config['topsecret.server.com']
topsecret['Host Port']='50022'    #子节点Host Port
topsecret['ForwardX11']='no'     #子节点ForwardX11

config["DEFAULT"]['ForwardX11'] = 'yes'#第一个节点的子节点ForwardX11

with open('example.ini','w') as configfile:
    config.write(configfile)
创建配置文件
#-*- coding:utf-8 -*-
#Author:'Yang'

import configparser

config=configparser.ConfigParser()

#
config.read("example.ini")
print(config.defaults())
print(config.defaults()['compression'])
print(config.sections())
读配置文件
#-*- coding:utf-8 -*-
#Author:'Yang'

import configparser

config=configparser.ConfigParser()

#删除节点bitbucket.org
sec=config.remove_section('bitbucket.org')
config.write(open('example.cfg','w'))
删除节点

10.hashlib                                                                                                                                                               

 hashlib模块,用于加密相关的操作,在python3.x中代替了md5模块和sha模块,主要提供SHA1、SHA224、 SHA256、SHA384、SHA512 、MD5 算法。

#-*- coding:utf-8 -*-
#Author:'Yang'

import hashlib

print("md5".center(150,"*"))
m=hashlib.md5()
m.update(b'Hello!')
print(m.digest())   #2进制格式hash
print(m.hexdigest())    #二进制格式hash
m.update(b"It's me")    #其实是拼接,输出是 Hello!It's me,看下面m2的输出是否相等就明白了
print(m.hexdigest())    #16进制式hash

m2=hashlib.md5()
m2.update(b"Hello!It's me")
print(m2.hexdigest())


print("sha1".center(150,"*"))   #一般不使用,最短
s=hashlib.sha1()
s.update(b'Hello!')
print(s.hexdigest())
s.update(b"It's me")
print(s.hexdigest())

s2=hashlib.sha1()
s2.update(b"Hello!It's me")
print(s2.hexdigest())

print("sha256".center(150,"*"))
s=hashlib.sha256()
s.update(b'Hello!')
print(s.hexdigest())
s.update(b"It's me")
print(s.hexdigest())

s2=hashlib.sha256()
s2.update(b"Hello!It's me")
print(s2.hexdigest())

print("sha384".center(150,"*"))
s=hashlib.sha384()
s.update(b'Hello!')
print(s.hexdigest())
s.update(b"It's me")
print(s.hexdigest())

s2=hashlib.sha384()
s2.update(b"Hello!It's me")
print(s2.hexdigest())

print("sha512".center(150,"*")) #这个是最长的
s=hashlib.sha512()
s.update(b'Hello!')
print(s.hexdigest())
s.update(b"It's me")
print(s.hexdigest())

s2=hashlib.sha512()
s2.update(b"Hello!It's me")
print(s2.hexdigest())
hashlib模块的几种算法

另外,python还有一个hmac模块,其内部对我们创建的key和value在进行处理后再加密

import hmac

#用于消息加密,特点是比较快
hm=hmac.new(b"Hello!","我是消息!".encode(encoding='utf-8'))
print(hm.hexdigest()) hm.update(
"你好!".encode(encoding='utf-8')) print(hm.hexdigest()) #16进制式

注意,如果在hashlib模块、hmac模块中要对中文进行加密,必须要encode,否则会报错。

11.re正则表达式                                                                                                                                                        

 正则表达式,是很重要的一块,直接进入代码认识re模块,

>>> import re
>>> re.match("^ABC","ABC123")    #^是以ABC开头,匹配到就会有输出,匹配不到就没有输出
<_sre.SRE_Match object; span=(0, 3), match='ABC'>
>>> re.match("^ABD","ABC123")
>>> res=re.match("^ABC","ABC123")
>>> print(res)
<_sre.SRE_Match object; span=(0, 3), match='ABC'>
>>> res.group()    #输出匹配项
'ABC'
>>> res=re.match("^ABC\d+","ABC123")    #\d是数字,+是多个,\d+多个数字
>>> res.group()
'ABC123'
View Code

常用正则表达式符号及常用方法(match,search,findall):

'.'    默认匹配除\n之外的任意一个字符,若指定flags=re.DOTALL则匹配任意字符,包括\n
>>> re.search(".","\nABC123")
<_sre.SRE_Match object; span=(1, 2), match='A'>
>>> re.match(".","\nABC123",flags=re.DOTALL)
<_sre.SRE_Match object; span=(0, 1), match='\n'>

'^'    匹配字符开头,若指定flags=re.MULTILINE,则re.search(r"^a","\nabc\neee",flags=re.MULTILINE)这种也可以匹配上,匹配结果为'a' 

'$'    匹配字符结尾,若指定flags=re.MULTILINE,则re.search("foo$","bfoo\naaa",flags=re.MULTILINE).group() 也可以匹配上,匹配结果为'foo' 
>>> re.search("foo$","bfoo\naaa",flags=re.MULTILINE)    #匹配得到
<_sre.SRE_Match object; span=(1, 4), match='foo'>
>>> re.search("foo$","bfoo\naaa")    #匹配不到
>>> re.search("foo$","bfoo")    #匹配得到
<_sre.SRE_Match object; span=(1, 4), match='foo'>
'*'    匹配*前的字符0次或多次,re.findall("ab*","cabb3abcbbac"),匹配结果为['abb', 'ab', 'a']

'+'    匹配前一个字符1次或多次
>>> re.findall("ab+","cabb3abcbbac")
['abb', 'ab']

'?'    匹配前一个字符1次或0次

'{m}'    匹配前一个字符m次

'{n,m}'    匹配前一个字符n到m次
>>> re.findall("ab{1,3}","abb abc abbbbbb abd")#匹配b 1到3次
['abb', 'ab', 'abbb', 'ab']

'|'    匹配|左或|右的字符
>>> re.search("abc|ABC","ABCBabcCD").group()
'ABC'
>>> re.search("abc|ABC","abcCDABCB").group()
'abc'

'(...)'    分组匹配
>>> re.search("(abc){2}a(123|456)c","abcabca456cdd").group()
'abcabca456c'
'\A'    只从字符开头匹配,re.search("\Aabc","Roseabc")是匹配不到的
'\Z'    匹配字符结尾,同$
'\d'    匹配数字0-9
'\D'    匹配非数字
'\w'    匹配[A-Za-z0-9]
'\W'    匹配非[A-Za-z0-9]
'\s'    匹配空白字符、\t、\n、\r
>>> re.search("\s+","ab\tc1\n3").group()
'\t'

'(?P<name>)'     分组匹配
>>> re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{8})","340122199001010000").groupdict()
{'province':'3401','city':'22','birthday':'19900101'}

 注意在匹配特殊字符时,需要加转义字符,如

>>> re.search("(abc){2}(\|\|=){2}","alexabcabc||=||=cc")  #如匹配管道符| 时,需要转义 \|
<_sre.SRE_Match object; span=(4, 16), match='abcabc||=||='>

 另外还有split方法

>>> re.split("[0-9]","abc12de3f45GH")  #用数字分割字符串
['abc', '', 'de', 'f', '', 'GH']

sub方法

>>> re.sub("[0-9]+","-","abc12de3f45GH")  #将匹配到的数字全部替换为“-”
'abc-de-f-GH'
>>> re.sub("[0-9]+","-","abc12de3f45GH",count=2)  #将匹配到的数字前2处替换为“-”
'abc-de-f45GH'

补充介绍一下,flags的一个参数(其实上面已经有介绍过flags的其他几个参数,细心的朋友应该已经了解了)

>>> re.search('[a-z]+',"ABBcccd",flags=re.I)  #re.I 忽略大小写
<_sre.SRE_Match object; span=(0, 7), match='ABBcccd'>

这里留一个小问题,如果字符串中包含"\",如何写正则表达式匹配呢?如“sssfffg\1234sad”,请写出正则表达式匹配"\"

12.subprocess                                                                                                                                                         

subprocess模块——创建附加进程 
subprocess模块提供了一种一致的方法来创建和处理附加进程,与标准库中的其它模块相比,提供了一个更高级的接口。用于替换如下模块: 
os.system() ,os.spawnv() ,os和popen2模块中的popen()函数,以及 commands()。

可以通过help(subprocess) 了解更多。

13.logging                                                                                                                                                                

logging模块提供了标准的日志接口,你可以通过它存储各种格式的日志,logging的日志可以分为 debug() info()warning(), error() 和 critical() 5个级别(级别由低到高

下面看一段代码,

import logging
logging.basicConfig(level=logging.ERROR) #如果不添加这一句,默认级别是WARNING
logging.warning("用户密码输入错误已达三次!")
logging.critical("服务器挂了。")

代码执行结果:
CRITICAL:root:服务器挂了。

对比下面这段代码,看看输出有什么不同?

import logging
logging.warning("用户密码输入错误已达三次!")
logging.critical("服务器挂了。")

代码执行结果:
WARNING:root:用户密码输入错误已达三次!
CRITICAL:root:服务器挂了。

总结:level=loggin.ERROR意思是,把日志记录级别设置为ERROR,只有比日志是ERROR或比ERROR级别更高的日志才会被记录,在第一段代码中第一条日志是不会输出的,如果希望记录warning的日志,那把日志级别改成WARNING就行了或者去掉 logging.basicConfig(level=logging.ERROR) 这行,因为不设置时,默认级别为WARNING。

如果想输出日志记录的时间,可以这样编写代码,

import logging
logging.basicConfig(format='%(asctime)s %(message)s',datefmt='%m/%d/%y %I:%M:%S %p')
logging.warning("is when this event was logged.")

代码执行结果:
07/17/17 04:23:07 PM is when this event was logged.

如果想把日志记录存储在文件中,代码如下,

import logging
#将日志记录存储在文件中
logging.basicConfig(filename='example.log',level=logging.INFO)
logging.debug("Detailed information, typically of interest only when diagnosing problems.")  #由于INFO级别高于debug,所以这句不会被记录
logging.info("Confirmation that things are working as expected.")
logging.warning("An indication that something unexpected happened, or indicative of some problem in the near future (e.g. ‘disk space low’). The software is still working as expected.")
logging.error("    Due to a more serious problem, the software has not been able to perform some function.")
logging.critical("A serious error, indicating that the program itself may be unable to continue running.")
View Code

贴张日志格式的表格,方便使用时查询,

%(name)s

Logger的名字

%(levelno)s

数字形式的日志级别

%(levelname)s

文本形式的日志级别

%(pathname)s

调用日志输出函数的模块的完整路径名,可能没有

%(filename)s

调用日志输出函数的模块的文件名

%(module)s

调用日志输出函数的模块名

%(funcName)s

调用日志输出函数的函数名

%(lineno)d

调用日志输出函数的语句所在的代码行

%(created)f

当前时间,用UNIX标准的表示时间的浮 点数表示

%(relativeCreated)d

输出日志信息时的,自Logger创建以 来的毫秒数

%(asctime)s

字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒

%(thread)d

线程ID。可能没有

%(threadName)s

线程名。可能没有

%(process)d

进程ID。可能没有

%(message)s

用户输出的消息

 

如果想同时把log打印在屏幕和文件日志里,就需要了解一点复杂的知识,直接敲代码,逐句解读:

#-*- coding:utf-8 -*-
#Author:'Yang'

import logging

#每个程序在输出信息之前都要获得一个Logger
logger=logging.getLogger('TEST-LOG')    #TEST-LOG是定义的logger名
logger.setLevel(logging.DEBUG)  #指定最低的日志级别,低于DEBUG的级别将被忽略,DEBUG是最低的内置级别,CRITICAL是最高级别

#输出到屏幕,每个Logger可以附加多个Handler
ch=logging.StreamHandler()  #使用这个Handler可以向类似于sys.stdout或者sys.stderr(默认是sys.stderr)的任何文件对象(file object)输出信息
ch.setLevel(logging.DEBUG)

#输出到日志文件
fh=logging.FileHandler("access.log")#和StreamHandler类似,用于向一个文件输出日志信息。不过FileHandler会帮你打开这个文件,所以必须指定一个文件名
fh.setLevel(logging.WARNING)

#设置时间输出格式
formatter=logging.Formatter('%(asctime)s-%(name)s-%(levelname)s-%(message)s')

ch.setFormatter(formatter)  #屏幕上的时间输出格式
fh.setFormatter(formatter)  #日志文件中的时间输出格式

logger.addHandler(ch)   #屏幕输出,增加指定的handler
logger.addHandler(fh)   #日志文件,增加指定的handler

logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')
View Code

注意输出,打印出了5条记录,而日志文件仅仅记录3条,这是为什么呢?请自行思考。

总结:Python 使用logging模块记录日志涉及四个主要类,使用官方文档中的概括:

logger提供了应用程序可以直接使用的接口;

handler将(logger创建的)日志记录发送到合适的目的输出;

filter提供了细度设备来决定输出哪条日志记录;

formatter决定日志记录的最终输出格式。

logger
每个程序在输出信息之前都要获得一个Logger。Logger通常对应了程序的模块名,比如聊天工具的图形界面模块可以这样获得它的Logger:
LOG=logging.getLogger(”chat.gui”)
而核心模块可以这样:
LOG=logging.getLogger(”chat.kernel”)

Logger.setLevel(lel):指定最低的日志级别,低于lel的级别将被忽略。debug是最低的内置级别,critical为最高
Logger.addFilter(filt)、Logger.removeFilter(filt):添加或删除指定的filter
Logger.addHandler(hdlr)、Logger.removeHandler(hdlr):增加或删除指定的handler
Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical():可以设置的日志级别
 

handler

handler对象负责发送相关的信息到指定目的地。Python的日志系统有多种Handler可以使用。有些Handler可以把信息输出到控制台,有些Logger可以把信息输出到文件,还有些 Handler可以把信息发送到网络上。如果觉得不够用,还可以编写自己的Handler。可以通过addHandler()方法添加多个多handler
Handler.setLevel(lel):指定被处理的信息级别,低于lel级别的信息将被忽略
Handler.setFormatter():给这个handler选择一个格式
Handler.addFilter(filt)、Handler.removeFilter(filt):新增或删除一个filter对象


每个Logger可以附加多个Handler。接下来我们就来介绍一些常用的Handler:
1) logging.StreamHandler
使用这个Handler可以向类似于sys.stdout或者sys.stderr的任何文件对象(file object)输出信息。它的构造函数是:
StreamHandler([strm])
其中strm参数是一个文件对象。默认是sys.stderr


2) logging.FileHandler
和StreamHandler类似,用于向一个文件输出日志信息。不过FileHandler会帮你打开这个文件。它的构造函数是:
FileHandler(filename[,mode])
filename是文件名,必须指定一个文件名。
mode是文件的打开方式。参见Python内置函数open()的用法。默认是’a',即添加到文件末尾。

3) logging.handlers.RotatingFileHandler
这个Handler类似于上面的FileHandler,但是它可以管理文件大小。当文件达到一定大小之后,它会自动将当前日志文件改名,然后创建 一个新的同名日志文件继续输出。比如日志文件是chat.log。当chat.log达到指定的大小之后,RotatingFileHandler自动把 文件改名为chat.log.1。不过,如果chat.log.1已经存在,会先把chat.log.1重命名为chat.log.2。。。最后重新创建 chat.log,继续输出日志信息。它的构造函数是:
RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
其中filename和mode两个参数和FileHandler一样。
maxBytes用于指定日志文件的最大文件大小。如果maxBytes为0,意味着日志文件可以无限大,这时上面描述的重命名过程就不会发生。
backupCount用于指定保留的备份文件的个数。比如,如果指定为2,当上面描述的重命名过程发生时,原有的chat.log.2并不会被更名,而是被删除。


4) logging.handlers.TimedRotatingFileHandler
这个Handler和RotatingFileHandler类似,不过,它没有通过判断文件大小来决定何时重新创建日志文件,而是间隔一定时间就 自动创建新的日志文件。重命名的过程与RotatingFileHandler类似,不过新的文件不是附加数字,而是当前时间。它的构造函数是:
TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义。
interval是时间间隔。
when参数是一个字符串。表示时间间隔的单位,不区分大小写。它有以下取值:
S 秒
M 分
H 小时
D 天
W 每星期(interval==0时代表星期一)
midnight 每天凌晨
logging模块各方法用法简介

 下面介绍一下,如何给自己的代码添加日志文件

#-*- coding:utf-8 -*-
#Author:'Yang'

import  logging

from logging import handlers

logger=logging.getLogger(__name__)  #获取当前文件名,并记录日志
log_file='timelog.log'  #日志名

fh=handlers.RotatingFileHandler(filename=log_file,maxBytes=0.1)    #maxBytes用于指定日志文件的最大文件大小。如果maxBytes为0,意味着日志文件可以无限大
#fh=handlers.TimedRotatingFileHandler(filename=log_file,when="S",interval=5,backupCount=3)   #backupCount用于指定保留的备份文件的个数

formatter=logging.Formatter('%(asctime)s %(module)s:%(lineno)d %(message)s')    #输出格式:时间-运行模块(即当前运行的.py文件)-信息输出行数-输出信息

fh.setFormatter(formatter)  #给fh这个handler选择一个格式

logger.addHandler(fh)   #增加指定的文件handler,不加这句话,后面的信息将直接输出打印,不存储在日志文件中

logger.warning("test1")
logger.warning("test2")
logger.warning("test3")
logger.warning("test4")
View Code

这段代码,就是一个文件自动截断的例子,大家可以试着给自己写过的代码加log日志。

14.练习                                                                                                                                                                     

开发一个简单的python计算器

1.实现加减乘除及括号优先级解析

2.用户输入 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )等类似公式后,必须自己解析里面的(),+,-,*,/符号和公式(不能调用eval等类似功能偷懒实现),运算后得出结果,结果必须与真实的计算器所得出的结果一致

 

hint:

re.search(r'\([^()]+\)',s).group()

'(-40/5)'

posted on 2017-06-20 14:40  奔跑的蜗牛~~  阅读(188)  评论(0)    收藏  举报

导航