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等類似功能偷懶實現),運算后得出結果,結果必須與真實的計算器所得出的結果一致