Day05 - 常用模塊學習

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.systemos.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:

  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 每天凌晨

十一、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數據類型間進行轉換,提供了四個功能:dumpsdumploadsload

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的數據類型間進行轉換,提供了四個功能:dumpsdumploadsload

  • 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反射

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容