Day05的课程要点记录
详细教程地址:Day5 - 常用模块学习 | 第四篇:模块
一、模块介绍
1.1 定义
模块,用一砣代码实现了某个功能的代码集合。
1.2 模块分类
- 自定义模块
- 内置标准模块(标准库)
- 开源模块
二、time
& datetime
模块
2.1 time
模块
import time
print(time.clock()) # 返回处理器时间,3.3开始已废弃 , 改成了time.process_time()测量处理器运算时间,不包括sleep时间,不稳定,mac上测不出来
print(time.altzone) # 返回与utc时间的时间差,以秒计算\
print(time.asctime()) # 返回时间格式"Fri Aug 19 11:14:16 2016",
print(time.localtime()) # 返回本地时间 的struct time对象格式
print(time.gmtime(time.time()-800000)) # 返回utc时间的struc时间对象格式
print(time.asctime(time.localtime())) # 返回时间格式"Fri Aug 19 11:14:16 2016",
print(time.ctime()) #返回Fri Aug 19 12:38:29 2016 格式, 同上
2.1.1 日期字符串 转成 时间戳
# string_2_struct = time.strptime("2016/05/22","%Y/%m/%d") #将 日期字符串 转成 struct时间对象格式
# print(string_2_struct)
# struct_2_stamp = time.mktime(string_2_struct) #将struct时间对象转成时间戳
# print(struct_2_stamp)
2.1.2 将时间戳转为字符串格式
# print(time.gmtime(time.time()-86640)) #将utc时间戳转换成struct_time格式
# print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()) ) #将utc struct_time格式转成指定的字符串格式
2.2 datetime
模块
2.2.1 时间加减
print(datetime.datetime.now()) #返回 2016-08-19 12:47:03.941925
print(datetime.datefromtimestamp(time.time()) ) # 时间戳直接转成日期格式 2016-08-19
print(datetime.datetime.now() )
print(datetime.datetime.now() + datetime.timedelta(3)) #当前时间+3天
print(datetime.datetime.now() + datetime.timedelta(-3)) #当前时间-3天
print(datetime.datetime.now() + datetime.timedelta(hours=3)) #当前时间+3小时
print(datetime.datetime.now() + datetime.timedelta(minutes=30)) #当前时间+30分
2.2.2 时间替换
c_time = datetime.datetime.now()
print(c_time.replace(minute=3,hour=2)) #
三、random
模块
3.1 随机数
import random
print(random.random()) # 随机打印小数
print(random.randint(1,5)) # 随机打印范围内整数
print(random.randrange(1,5)) # 随机打印范围内整数(不包含末尾数)
print(random.sample(range(100), 5)) # 随机从100个数字中选5个
3.2 生成随机验证码
import string
str_source = string.ascii_letters + string.digits
print(''.join(random.sample(str_source, 6)))
import random
checkcode = ''
for i in range(4):
current = random.randrange(0,4)
if current != i:
temp = chr(random.randint(65,90)) # 取大写字母 A-Z 之一
else:
temp = random.randint(0,9)
checkcode += str(temp)
print(checkcode)
四、shutil
模块
高级的文件、文件夹、压缩包处理模块
4.1 shutil.copyfileobj(fsrc, fdst[, length])
将文件内容拷贝到另一个文件中,可以部分内容
4.2 shutil.copy(src, dst)
拷贝文件和权限
4.3 shutil.copyfile(src, dst)
拷贝文件
4.4 shutil.copymode(src, dst)
仅拷贝权限。内容、组、用户均不变
4.5 shutil.copystat(src, dst)
拷贝状态的信息
包括:mode bits, atime, mtime, flags
4.6 shutil.copy2(src, dst)
拷贝文件和状态信息
4.7 shutil.copytree(src, dst, symlinks=False, ignore=None)
递归的去拷贝文件
拷贝目录
例如:copytree(source, destination, ignore=ignore_patterns('.pyc', 'tmp'))
4.8 shutil.rmtree(path[, ignore_errors[, onerror]])
递归的去删除文件
4.9 shutil.move(src, dst)
递归的去移动文件
4.10 shutil.make_archive(base_name, format,...)
创建压缩包并返回文件路径,例如:zip、tar
- base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,
如:www =>保存至当前路径
如:/Users/wupeiqi/www =>保存至/Users/wupeiqi/format: 压缩包种类,“zip”, - - “tar”, “bztar”,“gztar” - root_dir: 要压缩的文件夹路径(默认当前目录)
- owner: 用户,默认当前用户
- group: 组,默认当前组
- logger: 用于记录日志,通常是logging.Logger对象
五、shelve
模块
六、xml
模块
xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单。不过,在json还没诞生的年代,大家只能选择用xml,至今很多传统公司如金融行业的很多系统的接口还主要是xml。
6.1 xml 的格式
xml的格式如下,就是通过<>节点来区别数据结构的:
<?xml version="1.0"?>
<data>
<country name="Liechtenstein">
<rank updated="yes">2</rank>
<year>2008</year>
<gdppc>141100</gdppc>
<neighbor name="Austria" direction="E"/>
<neighbor name="Switzerland" direction="W"/>
</country>
<country name="Singapore">
<rank updated="yes">5</rank>
<year>2011</year>
<gdppc>59900</gdppc>
<neighbor name="Malaysia" direction="N"/>
</country>
<country name="Panama">
<rank updated="yes">69</rank>
<year>2011</year>
<gdppc>13600</gdppc>
<neighbor name="Costa Rica" direction="W"/>
<neighbor name="Colombia" direction="E"/>
</country>
</data>
6.2 Python中操作xml
xml协议在各个语言里的都是支持的,在python中可以用以下模块操作xml
import xml.etree.ElementTree as ET
tree = ET.parse("xmltest.xml")
root = tree.getroot()
print(root.tag)
#遍历xml文档
for child in root:
print(child.tag, child.attrib)
for i in child:
print(i.tag,i.text)
#只遍历year 节点
for node in root.iter('year'):
print(node.tag,node.text)
修改和删除xml文档内容
import xml.etree.ElementTree as ET
tree = ET.parse("xmltest.xml")
root = tree.getroot()
#修改
for node in root.iter('year'):
new_year = int(node.text) + 1
node.text = str(new_year)
node.set("updated","yes")
tree.write("xmltest.xml")
#删除node
for country in root.findall('country'):
rank = int(country.find('rank').text)
if rank > 50:
root.remove(country)
tree.write('output.xml')
自己创建xml文档
import xml.etree.ElementTree as ET
new_xml = ET.Element("namelist")
name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"})
age = ET.SubElement(name,"age",attrib={"checked":"no"})
sex = ET.SubElement(name,"sex")
sex.text = '33'
name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"})
age = ET.SubElement(name2,"age")
age.text = '19'
et = ET.ElementTree(new_xml) #生成文档对象
et.write("test.xml", encoding="utf-8",xml_declaration=True)
ET.dump(new_xml) #打印生成的格式
七、ConfigParser
模块
用于生成和修改常见配置文档,当前模块的名称在 python 3.x 版本中变更为 configparser。
常见文档
[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
[bitbucket.org]
User = hg
[topsecret.server.com]
Port = 50022
ForwardX11 = no
7.2 用Python生成一个文档
import configparser
config = configparser.ConfigParser()
config["DEFAULT"] = {'ServerAliveInterval': '45',
'Compression': 'yes',
'CompressionLevel': '9'}
config['bitbucket.org'] = {}
config['bitbucket.org']['User'] = 'hg'
config['topsecret.server.com'] = {}
topsecret = config['topsecret.server.com']
topsecret['Host Port'] = '50022' # mutates the parser
topsecret['ForwardX11'] = 'no' # same here
config['DEFAULT']['ForwardX11'] = 'yes'
with open('example.ini', 'w') as configfile:
config.write(configfile)
7.3 读取配置文件
import configparser
config = configparser.ConfigParser()
print(config.sections())
config.read('example.ini')
print(config.read('example.ini'))
print(config.sections())
print('bitbucket.org' in config)
print('byebong.com' in config)
print(config['bitbucket.org']['User'])
print(config['DEFAULT']['compression'])
topsecret = config['topsecret.server.com']
print(topsecret['ForwardX11'])
print(topsecret['Port'])
for key in config['bitbucket.org']:
print(key)
val1 = config.get('bitbucket.org', 'user')
val2 = config.getint('topsecret.server.com', 'port')
print(val1, val2)
7.3 改写配置文件
import configparser
config = configparser.ConfigParser()
config.read('example.ini')
config.remove_section('bitbucket.org') # 删除section
config.write(open('exmaple2.ini', 'w'))
config.has_section('www.server.com') # 如果有section
config.add_section('www.server.com') # 添加section
config.write(open('exmaple2.ini', 'w'))
config.set('topsecret.server.com', 'port', '3000') # 修改
config.write(open('exmaple2.ini', 'w'))
config.remove_option('topsecret.server.com', 'forwardx11') # 删除option中的值
config.write(open('exmaple2.ini', 'w'))
八、hashlib
模块
8.1 hashlib
模块用法
用于加密相关的操作,3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法
import hashlib
m = hashlib.md5()
m.update(b"Hello")
m.update(b"It's me")
print(m.digest())
m.update(b"It's been a long time since last time we ...")
print(m.digest()) #2进制格式hash
print(len(m.hexdigest())) #16进制格式hash
8.2 hashlib
模块举例
import hashlib
# ######## md5 ########
hash = hashlib.md5()
hash.update('admin')
print(hash.hexdigest())
# ######## sha1 ########
hash = hashlib.sha1()
hash.update('admin')
print(hash.hexdigest())
# ######## sha256 ########
hash = hashlib.sha256()
hash.update('admin')
print(hash.hexdigest())
# ######## sha384 ########
hash = hashlib.sha384()
hash.update('admin')
print(hash.hexdigest())
# ######## sha512 ########
hash = hashlib.sha512()
hash.update('admin')
print(hash.hexdigest())
8.3 hmac
模块
对我们创建 key 和 内容 再进行处理然后再加密
import hmac
h = hmac.new('wueiqi')
h.update('hellowo')
print h.hexdigest()
Subprocess
模块
逐步取代os.system
和os.spawn
模块
十、logging
模块
很多程序都有记录日志的需求,并且日志中包含的信息即有正常的程序访问日志,还可能有错误、警告等信息输出,python的logging模块提供了标准的日志接口,你可以通过它存储各种格式的日志。
10.1 简单用法
import logging
logging.warning("user [alex] attempted wrong password more than 3 times")
logging.critical("server is down")
logging的日志可以分为debug()
, info()
, warning()
, error()
and critical()
5个级别。
Level | When it’s used |
---|---|
DEBUG | Detailed information, typically of interest only when diagnosing problems. |
INFO | Confirmation that things are working as expected. |
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. |
ERROR | Due to a more serious problem, the software has not been able to perform some function. |
CRITICAL | A serious error, indicating that the program itself may be unable to continue running. |
10.2 将日志写入文件
import logging
logging.basicConfig(filename='example.log',level=logging.�INFO)
logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too')
句中的level=loggin.INFO意思是,把日志记录级别设置为INFO,也就是说,只有比日志是INFO或比INFO级别更高的日志才会被记录到文件里。
日志格式加上时间
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.')
方法 | 解释 | 方法 | 解释 |
---|---|---|---|
%(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 | 用户输出的消息 |
日志格式
方法 | 解释 | 方法 | 解释 |
---|---|---|---|
%(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 | 用户输出的消息 |
10.3 同时输出至文件和屏幕
Python 使用logging模块记录日志涉及四个主要类,使用官方文档中的概括最为合适:
logger提供了应用程序可以直接使用的接口;
handler将(logger创建的)日志记录发送到合适的目的输出;
filter提供了细度设备来决定输出哪条日志记录;
formatter决定日志记录的最终输出格式。
10.3.1 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():可以设置的日志级别
10.3.2 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:
logging.StreamHandler
使用这个Handler可以向类似与sys.stdout或者sys.stderr的任何文件对象(file object)输出信息。它的构造函数是:
StreamHandler([strm])
其中strm参数是一个文件对象。默认是sys.stderrlogging.FileHandler
和StreamHandler类似,用于向一个文件输出日志信息。不过FileHandler会帮你打开这个文件。它的构造函数是:
FileHandler(filename[,mode])
filename是文件名,必须指定一个文件名。
mode是文件的打开方式。参见Python内置函数open()的用法。默认是’a',即添加到文件末尾。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并不会被更名,而是被删除。logging.handlers.TimedRotatingFileHandler
这个Handler和RotatingFileHandler类似,不过,它没有通过判断文件大小来决定何时重新创建日志文件,而是间隔一定时间就 自动创建新的日志文件。重命名的过程与RotatingFileHandler类似,不过新的文件不是附加数字,而是当前时间。它的构造函数是:
TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义。
interval是时间间隔。
when参数是一个字符串。表示时间间隔的单位,不区分大小写。它有以下取值:
S 秒 | M 分 | H 小时 | D 天 | W 每星期(interval==0时代表星期一) | midnight 每天凌晨
十一、re
模块
11.1 常用正则表达式符号
'.' 默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行
'^' 匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a","\nabc\neee",flags=re.MULTILINE)
'$' 匹配字符结尾,或e.search("foo$","bfoo\nsdfsf",flags=re.MULTILINE).group()也可以
'*' 匹配*号前的字符0次或多次,re.findall("ab*","cabb3abcbbac") 结果为['abb', 'ab', 'a']
'+' 匹配前一个字符1次或多次,re.findall("ab+","ab+cd+abb+bba") 结果['ab', 'abb']
'?' 匹配前一个字符1次或0次
'{m}' 匹配前一个字符m次
'{n,m}' 匹配前一个字符n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 结果'abb', 'ab', 'abb']
'[]' 匹配'[]'内定义的任意字符,[]内字符不再有特殊意义(三个除外:'-' = 范围,'^' = 非,'\')
'|' 匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 结果'ABC'
'(...)' 分组匹配,re.search("(abc){2}a(123|456)c", "abcabca456c").group() 结果abcabca456c
'\': 反斜杠后跟元字符即去除特殊功能;跟普通字符即实现特殊功能;
'\A' 只从字符开头匹配,re.search("\Aabc","alexabc") 是匹配不到的
'\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'
'\S' 匹配非空白字符、\t、\n、\r , re.search("\s+","ab\tc1\n3").group() 结果 '\t'
'\b' 匹配单词边界,单词指连续的字母、数字和下划线组成的字符串。边界为空格或特殊字符。
'(?P<name>...)' 分组匹配 re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})","371481199306143242").groupdict("city") 结果{'province': '3714', 'city': '81', 'birthday': '1993'}
11.2 最常用的匹配语法
re.match 从头开始匹配
re.search 匹配包含
re.findall 把所有匹配到的字符放到以列表中的元素返回
re.split 以匹配到的字符当做列表分隔符
re.sub 匹配字符并替换 | re.sub 替换并给出替换次数
re.compile
11.3 re.findall
普通字符
>>> import re
>>> re.findall('alex', 'yuanaleSexalexwupeiqi')
['alex']
转译,加r
11.4 正则表达式的分组
去已经匹配到的数据中再提取数据
r.gourp() # 获取匹配到的所有结果
r.groups() # 获取模型中匹配到的分组结果
r.groupdict() # 获取模型中匹配到的分组结果
十二、sys
/ os
模块
12.1 sys模块
sys.argv 命令行参数List,第一个元素是程序本身路径
sys.exit(n) 退出程序,正常退出时exit(0)
sys.version 获取Python解释程序的版本信息
sys.maxint 最大的Int值
sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform 返回操作系统平台名称
sys.stdout.write('please:')
val = sys.stdin.readline()[:-1]
12.2 os模块
os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd
os.curdir 返回当前目录: ('.')
os.pardir 获取当前目录的父目录字符串名:('..')
os.makedirs('dirname1/dirname2') 可生成多层递归目录
os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname
os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove() 删除一个文件
os.rename("oldname","newname") 重命名文件/目录
os.stat('path/filename') 获取文件/目录信息
os.sep 输出操作系统特定的路径分隔符,win下为"\",Linux下为"/"
os.linesep 输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"
os.pathsep 输出用于分割文件路径的字符串
os.name 输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
os.system("bash command") 运行shell命令,直接显示
os.environ 获取系统环境变量
os.path.abspath(path) 返回path规范化的绝对路径
os.path.split(path) 将path分割成目录和文件名二元组返回
os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素
os.path.basename(path) 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False
os.path.isabs(path) 如果path是绝对路径,返回True
os.path.isfile(path) 如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回False
os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os.path.getatime(path) 返回path所指向的文件或者目录的最后存取时间
os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间
十三、Python序列化与反序列化
13.1 json
模块
用于字符串和python数据类型间进行转换,提供了四个功能:dumps
、dump
、loads
、load
13.1.1 dumps
将Python基本数据类型转换为字符串形式
>>> import json
>>> dic = {"k1": 123}
>>> print(dic, type(dic))
{'k1': 123} <class 'dict'>
>>> result = json.dumps(dic)
>>> print(result, type(result))
{"k1": 123} <class 'str'>
13.1.2 loads
将字符串形式转换为Python基本数据类型
>>> import json
>>> s1 = '{"k2": 321}'
>>> print(s1, type(s1))
{"k2": 321} <class 'str'>
>>> result = json.loads(s1)
>>> print(result, type(result))
{'k2': 321} <class 'dict'>
用loads
反序列化时,内部一定要用双引号"
13.1.3 dump
将Python基本数据类型转换为字符串形式,并且写入指定文件
>>> import json
>>> li = [11, 22, 33]
>>> json.dump(li, open('json_li', 'w', encoding='utf-8'))
13.1.4 load
将指定文件中的字符串形式转换为Python基本数据类型
>>> import json
>>> li2 = json.load(open('json_li', 'r', encoding='utf-8'))
>>> print(li2)
>>> [11, 22, 33]
13.2 pickle
模块
用于python特有的类型 和 python的数据类型间进行转换,提供了四个功能:dumps
、dump
、loads
、load
-
json
只能处理基本数据类型(如元组、列表、字典),更适合跨语言。 -
pickle
对python所有类型做序列化操作,仅适用于Python,版本不同也可能出错。
13.2.1 dumps
& loads
>>> import pickle
>>> li = [11, 22, 33]
# 将数据通过特殊的形式转换为只有Python语言认识的字符串
>>> res = pickle.dumps(li)
>>> print(res, type(res))
b'\x80\x03]q\x00(K\x0bK\x16K!e.' <class 'bytes'>
# 将只有Python语言认识的字符串转换为数据
>>> result = pickle.loads(res)
>>> print(result, type(result))
[11, 22, 33] <class 'list'>
13.2.2 dump
& load
>>> import pickle
>>> li = [11, 22, 33]
# 将数据通过特殊的形式转换为只有Python语言认识的字符串,并写入文件
>>> pickle.dump(li, open('pickle_li', 'wb'))
# 将文件中只有Python语言认识的字符串转换为数据
>>> result = pickle.load(open('pickle_li', 'rb'))
>>> print(result, type(result))
[11, 22, 33] <class 'list'>
十四、Python反射
14.1 web实例
考虑有这么一个场景,根据用户输入的url的不同,调用不同的函数,实现不同的操作,也就是一个url路由器的功能,这在web框架里是核心部件之一。
下面有一个精简版的示例:
14.1.1 首先,有一个commons模块,它里面有几个函数,分别用于展示不同的页面,代码如下:
def login():
print("这是一个登陆页面!")
def logout():
print("这是一个退出页面!")
def home():
print("这是网站主页面!")
14.1.2 其次,有一个visit模块,作为程序入口,接受用户输入,展示相应的页面,代码如下:(这段代码是比较初级的写法)
import commons
def run():
inp = input("请输入您想访问页面的url: ").strip()
if inp == "login":
commons.login()
elif inp == "logout":
commons.logout()
elif inp == "home":
commons.home()
else:
print("404")
if __name__ == '__main__':
run()
这就实现了一个简单的WEB路由功能,根据不同的url,执行不同的函数,获得不同的页面。
然而,如果commons模块里有成百上千个函数呢?
难道你在visit模块里写上成百上千个elif?
显然这是不可能的!
那么怎么破?
14.2 反射机制
仔细观察visit中的代码,我们会发现用户输入的url字符串和相应调用的函数名好像!如果能用这个字符串直接调用函数就好了!但是,前面我们已经说了字符串是不能用来调用函数的。
为了解决这个问题,python为我们提供了强大的内置函数:getattr
- 寻找、hasattr
- 检查、delattr
- 删除、setattr
- 设置
python提供了一个特殊的方法:import(字符串参数)。通过它,我们就可以实现类似的反射功能。import()方法会根据参数,动态的导入同名的模块。
反射:利用字符串的形式去对象(默认)中操作(寻找/检查/删除/设置)成员
14.2.1 实现
def run():
inp = input("请输入您想访问页面的url: ").strip()
if hasattr(commons, inp):
func = getattr(commons, inp)
func()
else:
print("404")
if __name__ == '__main__':
run()
14.2.2 动态导入模块
def run():
inp = input("请输入您想访问页面的url: ").strip()
m, f = inp.split('/')
obj = __import__(m)
if hasattr(obj, f):
func = getattr(obj, f)
func()
else:
print("404")
if __name__ == '__main__':
run()
如果模块不在一个目录:
def run():
inp = input("请输入您想访问页面的url: ").strip()
m, f = inp.split('/')
obj = __import__("lib." + m, fromlist=True) # 注意fromlist参数
if hasattr(obj, f):
func = getattr(obj, f)
func()
else:
print("404")
if __name__ == '__main__':
run()
作业:ATM和计算器
1. ATM:模拟实现一个ATM + 购物商城程序
额度 15000或自定义
实现购物商城,买东西加入 购物车,调用信用卡接口结账
可以提现,手续费5%
支持多账户登录
支持账户间转账
记录每月日常消费流水
提供还款接口
ATM记录操作日志
提供管理接口,包括添加账户、用户额度,冻结账户等。。。
用户认证用装饰器
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等类似功能偷懒实现),运算后得出结果,结果必须与真实的计算器所得出的结果一致