time、random以及序列化模塊

1、 time模塊 

 在Python中,一般有這幾種方式來表示時間:python

  • 時間戳(timestamp):一般來講,時間戳表示的是從1970年1月1日00:00:00開始按秒計算的偏移量。咱們運行「type(time.time())」,返回的是float類型
  • 格式化的時間字符串(Format String)
    • 結構化的時間(struct_time):struct_time元組共有9個元素共九個元素:(年,月,日,時,分,秒,一年中第幾周,一年中第幾天,夏令時),能夠經過點來調用具體裏面的值
      import time
      #--------------------------咱們先以當前時間爲準,讓你們快速認識三種形式的時間
      print(time.time()) # 時間戳:1487130156.419527
      f = time.localtime(time.time() - 86000 * 3)  # 150000000 秒  86000,三天前的結構化時間
      print(time.strftime("%Y-%m-%d %X")) #格式化的時間字符串:'2017-02-15 11:40:53',當前字符串時間
      print(time.strftime('%Y-%m-%d %H:%M:%S',f)) # f是結構化時間 將結構化時間轉化爲字符串時間
      print(time.localtime()) #本地時區的struct_time print(time.gmtime()) #UTC時區的struct_time
      %y 兩位數的年份表示(00-99%Y 四位數的年份表示(000-9999%m 月份(01-12%d 月內中的一天(0-31%H 24小時制小時數(0-23%I 12小時制小時數(01-12%M 分鐘數(00=59%S 秒(00-59%a 本地簡化星期名稱
      %A 本地完整星期名稱
      %b 本地簡化的月份名稱
      %B 本地完整的月份名稱
      %c 本地相應的日期表示和時間表示
      %j 年內的一天(001-366%p 本地A.M.或P.M.的等價符
      %U 一年中的星期數(00-53)星期天爲星期的開始
      %w 星期(0-6),星期天爲星期的開始
      %W 一年中的星期數(00-53)星期一爲星期的開始
      %x 本地相應的日期表示
      %X 本地相應的時間表示
      %Z 當前時區的名稱
      相應參數

       

    •     其中計算機認識的時間只能是'時間戳'格式,而程序員可處理的或者說人類能看懂的時間有: '格式化的時間字符串','結構化的時間' ,因而有了下圖的轉換關係mysql

 結合上圖可得:linux

#--------------------------按圖1轉換時間 1localtime([secs])將一個時間戳轉換爲當前時區的struct_time。secs參數未提供,則以當前時間爲準。
time.localtime() # time.struct_time(tm_year=2018, tm_mon=9, tm_mday=6, tm_hour=20, tm_min=56, tm_sec=16, tm_wday=3, tm_yday=249, tm_isdst=0)  當前時間
time.localtime(1473525444.037215) # time.struct_time(tm_year=2016, tm_mon=9, tm_mday=11, tm_hour=0, tm_min=37, tm_sec=24, tm_wday=6, tm_yday=255, tm_isdst=0) 給定時間的格式化時間 

2gmtime([secs]) 和localtime()方法相似,gmtime()方法是將一個時間戳轉換爲UTC時區(0時區)的struct_time time.gmtime() # 結果 time.struct_time(tm_year=2011, tm_mon=5, tm_mday=5, tm_hour=6, tm_min=19,tm_sec=48, tm_wday=3, tm_yday=125, tm_isdst=0)
 
 
三、mktime(t) : 將一個struct_time轉化爲時間戳。
print(time.mktime(time.localtime())) #1473525749.0
 四、strftime(format[, t]) : 把一個表明時間的元組或者struct_time(如由time.localtime()和time.gmtime()返回)轉化爲格式化的時間字符串。若是t未指定,將傳入time.localtime()。
    #若是元組中任何一個
元素越界,ValueError的錯誤將會被拋出 print(time.strftime("%Y-%m-%d %X", time.localtime())) #2016-09-11 00:49:56
print(time.strftime('%Y--%m--%d %X',)) #2018--09--06 21:04:16
# 五、time.strptime(string[, format]) # 把一個格式化時間字符串轉化爲struct_time。實際上它和strftime()是逆操做

print(time.strptime('2011-05-05 16:37:06', '%Y-%m-%d %X')) #time.struct_time(tm_year=2011, tm_mon=5, tm_mday=5, tm_hour=16, tm_min=37, tm_sec=6, # tm_wday=3, tm_yday=125, tm_isdst=-1)
#
在這個函數中,format默認爲:"%a %b %d %H:%M:%S %Y"。

總結:

    time是datetime的底層模塊
    時間戳時間-localtime/gmtime-> 結構化時間 -strftime-> 格式化時間
    時間戳時間<-mktime- 結構化時間 <-strptime- 格式化時間程序員

 
 time.time() # 獲取時間戳
 時間戳 --localtime('時間戳')--> 結構化時間 結構化時間--mktime('結構化時間')--> 時間戳 結構化時間--strftime('格式','結構化時間')-->  結構化的字符串  # 能夠格式自定義,
 結構化字符串時間 --strptime('結構化時間','格式')--> 結構化時間  # 必須參數一一對應

 

 

1、當前年月日的凌晨12點對應的時間戳時間是多少
today =time.strftime('%Y-%m-%d')  # 格式化時間
locals_time=time.strptime(today,'%Y-%m-%d')  #  獲取到結構化時間,默認返回凌晨時間
print(time.mktime(locals_time))   # 獲取時間戳
today =time.strftime('%Y-%m-%d %X')  # 格式化時間
locals_time=time.strptime(today,'%Y-%m-%d %X')  #  獲取到結構化時間,默認返回當前時間
print(time.mktime(locals_time))   # 獲取時間戳
print(time.time())
公司內的時間操做  
例題:
1、將s時間往前推30天
import time
s = '2019-03-20 10:40:00'
local_time = time.strptime(s,'%Y-%m-%d %X') # 轉化成結構化時間
print(local_time) #time.struct_time(tm_year=2019, tm_mon=3, tm_mday=20, tm_hour=10, tm_min=40, tm_sec=0, tm_wday              =2, tm_yday=79, tm_isdst=-1)
x=time.mktime(local_time)+30 * 86000   # 轉化成時間戳
new_time = time.localtime(x) #將時間戳轉化爲結構化時間
print(new_time)
new_time_local =time.strftime('%Y-%m-%d %X',new_time) # 將結構化時間轉化爲字符串格式
print(new_time_local)

#準確答案
import datetime
#將當前時間推前30天
print(datetime.datetime.now()-datetime.timedelta(30))
當前推後30天

 

 

 

含有月份週期的時間表示:web

 

 結合上圖可得:sql

#--------------------------按圖2轉換時間 # asctime([t]) : 把一個表示時間的元組或者struct_time表示爲這種形式:'Sun Jun 20 23:21:05 1993'。 # 若是沒有參數,將會將time.localtime()做爲參數傳入。
print(time.asctime())#Sun Sep 11 00:43:43 2016

# ctime([secs]) : 把一個時間戳(按秒計算的浮點數)轉化爲time.asctime()的形式。若是參數未給或者爲 # None的時候,將會默認time.time()爲參數。它的做用至關於time.asctime(time.localtime(secs))。
print(time.ctime())  # Sun Sep 11 00:46:38 2016
print(time.ctime(time.time()))  # Sun Sep 11 00:46:38 2016
輸入某年某月某日,判斷是這一年中的第幾天?(用內置模塊實現)

import time
input_ = input('請輸入年月日:')
time_local = time.strptime(input_,'%Y-%m-%d %X')
print(time_local.tm_yday)  # 結構化時間調用裏面的參數
結構化時間點功能

 補充shell

  一、time.clock():這個須要注意,在不一樣的系統上含義不一樣。在UNIX系統上,它返回的是「進程時間」,它是用秒錶示的浮點數(時間戳)。而在WINDOWS中,第一次調用,返回的是進程運行的實際時間。而第二次以後的調用是自第一次調用之後到如今的運行時間。(其實是以WIN32上QueryPerformanceCounter()爲基礎,它比毫秒錶示更爲精確)也就是CPU工做時間。數據庫

  二、time.sleep(secs):線程推遲指定的時間運行。單位爲秒編程


 2、datetime模塊json

#時間加減
import datetime

# print(datetime.datetime.now()) #返回 2016-08-19 12:47:03.941925,返回當前時間
# print(datetime.date.fromtimestamp(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分

# c_time  = datetime.datetime.now()
# print(c_time.replace(minute=3,hour=2)) #時間替換 2018-09-07 02:03:37.591115 其實就是修改時間

import datetime
t = datetime.datetime.now() # 時間操做符獲取對象
print(t.date())   # 就能夠訪問具體的天數
print(t.time())
print(t.timestamp())  #時間戳
print(t.day)
print(t.month)

from datetime import datetime,timedelta  # 從xx導入 建議
print(datetime.now() - timedelta(3))    # 進行加減天數
timedelta功能

 


 3、random模塊 

import random print(random.random()) #(0,1)----float 大於0且小於1之間的小數 print(random.randint(1,3))  #[1,3] 大於等於1且小於等於3之間的整數 print(random.randrange(1,3)) #[1,3) 大於等於1且小於3之間的整數 print(random.choice([1,'23',[4,5]]))  #1或者23或者[4,5],這裏能夠填字符串,在字符串中隨機一個字母  
print(random.choices([1,'23',[4,5],'3','4'],k=3)) #['4', '23', '23'],隨機3個

print(random.sample([1,'23',[4,5]],2)) #列表元素任意2個組合 print(random.uniform(1,3)) #大於1小於3的小數,如1.927109612082716 item=[1,3,5,7,9] random.shuffle(item) #打亂item的順序,至關於"洗牌" print(item)

例: 驗證碼生成器:
import random
def make_code(n):
res = ''
for i in range(n):
s1 = chr(random.randint(65,90)) # 生成字母chr
s2 = str(random.randint(0,9))
res += random.choice([s1,s2])
return res
print(make_code(9)) # H53FVG8K4
 

 


 4、os模塊

  os模塊是與操做系統交互的一個接口

import os print(os.getcwd())   # 獲取當前工做目錄,即當前python腳本工做的目錄路徑 D:\pycharm code\離校\時間模塊
 os.chdir("D:\pycharm code\day2")  # 改變當前腳本工做目錄;至關於shell下cd
print(os.getcwd())  # D:\pycharm code\day2 當再一次判斷位置時,發生了變化

# print(os.curdir) # . # print(os.pardir) # ..

# os.makedirs('abc\\alex') # 在day2(當前工做目錄)下生成abc文件,在abc下再生成alex文件 # os.makedirs('dirname1/dirname2') # 可生成多層遞歸目錄 (已存在的文件名不能再一次生成)

#os.removedirs('dirname1/dirname2') # 若目錄爲空,則刪除,並遞歸到上一級目錄,如若也爲空,則刪除,依此類推

# os.mkdir('dirname') # 生成單級目錄;至關於shell中mkdir dirname # os.rmdir('dirname') # 刪除單級空目錄,若目錄不爲空則沒法刪除,報錯;至關於shell中rmdir dirname

#print(os.listdir('.'))  # 列出指定目錄下的全部文件和子目錄,包括隱藏文件,並以列表方式打印,['abc', '今日大綱', '做業講解.py']

# os.remove('哈哈哈') # 刪除一個文件 # os.rename("abc","newname") # 重命名文件/目錄 舊名字,新名字

print(os.stat('./newname')) # 獲取文件目錄信息('path/filename') os.stat_result(st_mode=16895, st_ino=2533274790436658,       # st_dev=2092381065,st_nlink=1, st_uid=0, st_gid=0, st_size=0, st_atime=1536304047, st_mtime=1536300456,st_ctime=1536300456)
s = os.stat('./newname') print(s.st_size)   # 可打印文件大小

print(os.sep)   # 輸出操做系統特定的路徑分隔符,win下爲"\\",Linux下爲"/"
s=os.linesep     # 輸出當前平臺使用的行終止符,win下爲"\r\n",Linux下爲"\n",Mac下爲 '\r'
print('c,jjj%s'%s,end=' ') print('哈哈') print(os.pathsep)    # 輸出用於分割文件路徑的字符串 win下爲;,Linux下爲:
print(os.name)    # 輸出字符串指示當前使用平臺。win->'nt'; Linux->'posix'

#os.system("ping www.baidu.com -t") # 運行shell命令,直接顯示,cmd窗口 # print(os.environ) # 獲取系統環境變量 # print(os.path.abspath('D:\BaiduNetdiskDownload')) # 返回path規範化的絕對路徑

print(os.path.split('D:\BaiduNetdiskDownload'))  # 將path分割成目錄和文件名二元組返回 ('D:\\', 'BaiduNetdiskDownload')
print(os.path.dirname('D:\BaiduNetdiskDownload'))  # 返回path的目錄。其實就是os.path.split(path)的第一個元素 D:\
print(os.path.basename('D:\BaiduNetdiskDownload'))  # 返回path最後的文件名。如何path以/或\結尾,那麼就會返回空值 # 即os.path.split(path)的第二個元素 BaiduNetdiskDownload

print(os.path.exists('D:\BaiduNetdiskDownload')) # 若是path存在,返回True;若是path不存在,返回False True
print(os.path.isabs('D:\BaiduNetdiskDownload'))  # 若是path是絕對路徑,返回True True
print(os.path.isfile('D:\BaiduNetdiskDownload'))  # 若是path是一個存在的文件,返回True。不然返回False False
print(os.path.isdir('D:\BaiduNetdiskDownload'))  # 若是path是一個存在的目錄,則返回True。不然返回False True 
#os.path.join(path1[, path2[, ...]]) # 將多個路徑組合後返回,第一個絕對路徑以前的參數將被忽略
print(os.path.join('/my/','name/is/','vampire_techking'))  # /my/name/is/vampire_techking,注意這裏的第二個參數不能以/開頭

print(os.path.getatime('D:\BaiduNetdiskDownload'))  # 返回path所指向的文件或者目錄的最後存取時間 1536305083.0908828
print(os.path.getmtime('D:\BaiduNetdiskDownload'))  # 返回path所指向的文件或者目錄的最後修改時間
print(os.path.getsize('D:\BaiduNetdiskDownload'))  # 返回path的大小 

簡要總結:

os.path.abspath(path) #返回絕對路徑
os.path.basename(path) #返回文件名
os.path.commonprefix(list) #返回list(多個路徑)中,全部path共有的最長的路徑。
os.path.dirname(path) #返回文件路徑
os.path.exists(path)  #路徑存在則返回True,路徑損壞返回False
os.path.expanduser(path)  #把path中包含的"~"和"~user"轉換成用戶目錄
os.path.expandvars(path)  #根據環境變量的值替換path中包含的」$name」和」${name}」
os.path.getatime(path)  #返回最後一次進入此path的時間。
os.path.getmtime(path)  #返回在此path下最後一次修改的時間。
os.path.getctime(path)  #返回path的大小
os.path.getsize(path)  #返回文件大小,若是文件不存在就返回錯誤
os.path.isabs(path)  #判斷是否爲絕對路徑
os.path.isfile(path)  #判斷路徑是否爲文件
os.path.isdir(path)  #判斷路徑是否爲目錄
os.path.islink(path)  #判斷路徑是否爲連接
os.path.ismount(path)  #判斷路徑是否爲掛載點()
os.path.join(path1[, path2[, ...]])  #把目錄和文件名合成一個路徑
os.path.normcase(path)  #轉換path的大小寫和斜槓
os.path.normpath(path)  #規範path字符串形式
os.path.realpath(path)  #返回path的真實路徑
os.path.relpath(path[, start])  #從start開始計算相對路徑
os.path.samefile(path1, path2)  #判斷目錄或文件是否相同
os.path.sameopenfile(fp1, fp2)  #判斷fp1和fp2是否指向同一文件
os.path.samestat(stat1, stat2)  #判斷stat tuple stat1和stat2是否指向同一個文件
os.path.split(path)  #把路徑分割成dirname和basename,返回一個元組
os.path.splitdrive(path)   #通常用在windows下,返回驅動器名和路徑組成的元組
os.path.splitext(path)  #分割路徑,返回路徑名和文件擴展名的元組
os.path.splitunc(path)  #把路徑分割爲加載點與文件
os.path.walk(path, visit, arg)  #遍歷path,進入每一個目錄都調用visit函數,visit函數必須有
3個參數(arg, dirname, names),dirname表示當前目錄的目錄名,names表明當前目錄下的全部文件名,args則爲walk的第三個參數
os.path.supports_unicode_filenames  #設置是否支持unicode路徑名


在Linux和Mac平臺上,該函數會原樣返回path,在windows平臺上會將路徑中全部字符轉換爲小寫,並將全部斜槓轉換爲飯斜槓。
>>> os.path.normcase('c:/windows\\system32\\')   
'c:\\windows\\system32\\'   
   
規範化路徑,如..和/
>>> os.path.normpath('c://windows\\System32\\../Temp/')   
'c:\\windows\\Temp'   

>>> a='/Users/jieli/test1/\\\a1/\\\\aa.py/../..'
>>> print(os.path.normpath(a))
/Users/jieli/test1
1、os.walk() 方法用於經過在目錄樹中游走輸出在目錄中的文件名,向上或者向下。
格式:os.walk(top[, topdown=True[, onerror=None[, followlinks=False]]])
top -- 是你所要遍歷的目錄的地址, 返回的是一個三元組(root,dirs,files)。

    root 所指的是當前正在遍歷的這個文件夾的自己的地址
    dirs 是一個 list ,內容是該文件夾中全部的目錄的名字(不包括子目錄)
    files 一樣是 list , 內容是該文件夾中全部的文件(不包括子目錄)
topdown --可選,爲 True,則優先遍歷 top 目錄,不然優先遍歷 top 的子目錄            (默認爲開啓)。若是 topdown 參數爲 True,walk 會遍歷top文件夾,與top 文件夾中每個子目錄。
onerror -- 可選,須要一個 callable 對象,當 walk 須要異常時,會調用。
followlinks -- 可選,若是爲 True,則會遍歷目錄下的快捷方式(linux 下是軟鏈接 symbolic link )實際所指的目錄(默認關閉),若是爲 False,則優先遍歷 top 的子目錄。



import os
for root, dirs, files in os.walk(".", topdown=False):
    for name in files:
        print(os.path.join(root, name))
    for name in dirs:
        print(os.path.join(root, name))     

運行結果:
./.bash_logout
./amrood.tar.gz
./.emacs
./httpd.conf
./www.tar.gz
./mysql.tar.gz
./test.py
./.bashrc
./.bash_history
./.bash_profile
./tmp
./tmp/test.py
walk函數的使用

 


 5、sys模塊

   sys是與Python解釋器交互

    一、sys.argv     命令行參數List,第一個元素是程序自己路徑

     這個time.py文件的內容以下:

 

  不難看出這個程序,把咱們在外部傳入的post傳入在這個sys.argv中且是個列表,固然傳入的參數個數任意多。
對其進行改進!
import sys

# print(sys.argv)

def updata():
    print('上傳!!!')

def download():
    print('download……')

if sys.argv[1] == 'post':
    updata()
elif sys.argv[1] =='download':
    download()

 

 結果:

 

import sys sys.argv # 命令行參數List,第一個元素是程序自己路徑sys.exit(n) # 退出程序,正常退出時exit(0) n 爲其餘數時,都存在其餘異常退出,顯示1

print(sys.version)       # 獲取Python解釋程序的版本信息 # sys.maxint # 最大的Int值

print(sys.path )      # 返回模塊的搜索路徑,初始化時使用PYTHONPATH環境變量的值 會查找環境變量,固然最開始是從就近的工做文件找sys.path.append() # 能夠添加查找給出的絕對目錄,添加到列表中
print(sys.platform)       # 返回操做系統平臺名稱 # win32 或則 linux

sys.stdout.write('#') # 向終端打印標準化輸出 print就是用這個方法作出來的
sys.moudles # 是一個全局字典,該字典是python啓動後就加載在內存中。每當程序員導入新的模塊,將自動記錄該模塊
sys.modules

 進度條打印實例:

import sys
import time
import random

def progress(percent, width=50):
    if percent >= 1:
        percent = 1   # 百分比保證100%
    show_str = ('[%%-%ds]'%width)%(int(width*percent)*'#')
    print('\r%s %d%%'%(show_str,int(100*percent)),file=sys.stdout,flush=True,end='')

data_size = 1025
recv_size = 0
while recv_size < data_size:
    s = random.random()
    time.sleep(s) # 模擬數據的傳輸延遲
    recv_size += 50 # 每次收1024

    percent = recv_size/data_size  # 接收的比例
    progress(percent,width=70)import sys
import time
import random

def progress(percent, width=50):
    if percent >= 1:
        percent = 1   # 百分比保證100%
    show_str = ('[%%-%ds]'%width)%(int(width*percent)*'#')
    print('\r%s %d%%'%(show_str,int(100*percent)),file=sys.stdout,flush=True,end='')

data_size = 1025
recv_size = 0
while recv_size < data_size:
    s = random.random()
    time.sleep(s) # 模擬數據的傳輸延遲
    recv_size += 50 # 每次收1024

    percent = recv_size/data_size  # 接收的比例
    progress(percent,width=70)

 

補充print知識點:

print()函數的參數以下:
    print(*values, sep=' ', end='\n', file=sys.stdout, flush=False)


一、 *values : 表示要打印的值 
    表示任何多個無名參數, 各個值之間用‘,’(逗號隔開),打印出來各個值之間用空格隔開

二、sep=’ ‘: 表示當輸入多個打印的值時,各個值之間分割方式, 默認空格,能夠自定義
     例:print('a','m','c',sep='\n')   #  a m c 換行

三、 end=‘\n’**: 控制print中傳入值輸出完後結束符號,默認換行,這裏能夠設置爲其餘,如 ‘\t’, ’ ’ 等等, 能夠本身定義
    例:print('python', end=' ')
          print('is good')        # python is good

四、file=sys.stdout:設置輸出設備,及把print中的值打印到什麼地方,默認輸出到準端,能夠設置file= 文件儲存對象,把內容存到該文件中
    例:f = open(r'a.txt', 'w')
         print('python is good', file=f)
         f.close()
     # 則把python is good保存到 a.txt 文件中  

五、flush=False: 該參數主要是刷新, 默認False,不刷新,Ture時刷新,例如在上面 4 中print中設置:

  f = open(r'a.txt', 'w')
  print('python is good', file=f, flush=True)
# print到f中的內容先從到內存中,
當文件對象關閉時才把內容輸出到 a.txt 中,當flush=True時它會當即把內容刷新存到 a.txt 中

 

6、序列化模塊json、pickle、shelve簡述

  什麼叫序列化——將由原來的字典、列表等內容轉換成一個字符串的過程就叫作序列化,反序列化就是將字符串或則字節轉化成原先的數據類型。

序列化的目的;

  一、以某種存儲形式使自定義對象持久化;

  二、將對象從一個地方傳遞到另外一個地方;

  三、使程序更具備維護.

# a發送以一個數據給b,因爲發送數據,必須是二進制。因此須要經歷編碼到解碼的過程

dic = {'a':(1,2,3)}
s = str(dic).encode(encoding='utf-8')  # 編碼
ret = s.decode(encoding='utf-8')  # 解碼
print(ret)  # 查看數據
print(type(ret))  # 查看類型
print(type(eval(ret)))  # 還原爲字典  eval將字符串轉換爲字典


# 結果:
{'a': (1, 2, 3)}
<class 'str'>
<class 'dict'>

使用eval不安全,有多是病毒,接收方,啪的一些,就執行了。

這個時候,就須要用到序列化了

如上圖,可知:

  dic        -->  字符串 序列化
  字符串  -->  dic 反序列化
  序列化  ==  創造一個序列  ==》 創造一個字符串
  實例化  ==  創造一個實例

 

在Python中的序列化模塊:

    json     全部的編程語言都通用的序列化格式
    它支持的數據類型很是有限 數字 字符串 列表 字典。
  pickle         只能在python語言的程序之間傳遞數據用的
    pickle支持python中全部的數據類型。
  shelve   python3.* 以後纔有的,能夠把它看成字典處理。

  


 

7、Json模塊

Json模塊提供四個功能:dumps、dump、loads、load,除了能夠序列化字典還能夠序列化列表等。注意Json操做的是字符串,因此在打開讀寫文件的時候使用‘w'和’r‘模式

序列化(dumps,dump)

import json  # 導入模塊
dic = {"慕容美雪":(170,60,'賞花')}      # 鍵必須加雙引號
ret = json.dumps(dic)  # 序列化
print(type(dic),dic)  # 查看原始數據類型
print(type(ret),ret)  # 查看序列化後的數據

<class 'dict'> {'慕容美雪': (170, 60, '賞花')}
<class 'str'> {"\u6155\u5bb9\u7f8e\u96ea": [170, 60, "\u8d4f\u82b1"]}

從結果中,能夠看出:
原始數據類型是字典,序列化以後,就是字符串類型。並且中文變成了看不懂的字符串。
這是由於json.dumps 序列化時對中文默認使用的ascii編碼。
想輸出真正的中文須要指定ensure_ascii=False


import json  # 導入模塊
dic = {"慕容美雪":(170,60,'賞花')}
ret = json.dumps(dic,ensure_ascii=False)  # 序列化時,不使用ascii碼
print(type(dic),dic)  # 查看原始數據類型
print(type(ret),ret)  # 查看序列化後的數據

<class 'dict'> {'慕容美雪': (170, 60, '賞花')}
<class 'str'> {"慕容美雪": [170, 60, "賞花"]}

因爲json不識別元組,json認爲元組和列表是一回事,因此變成了列表。
在json中,引號,統一使用雙引號

反序列化 (loads,load)

import json  # 導入模塊
dic = {"慕容美雪":(170,60,'賞花')}
ret = json.dumps(dic,ensure_ascii=False)  # 序列化時,不使用ascii碼
res = json.loads(ret)  # 反序列化
print(type(res),res)  # 查看反序列化後的數據

執行輸出:

<class 'dict'> {'慕容美雪': [170, 60, '賞花']}

從結果中,能夠看出,原來的單引號由還原回來了。
反序列化,比eval要安全。因此eval儘可能少用。

 

注意: dump和load是直接將對象序列化以後寫入文件,且依賴一個文件句柄而dumps和loads是直接在文件中進行操做,固然能夠能夠經過文件的‘w'模式寫入。

dump 將序列化內容寫入文件
import json  # 導入模塊
dic = {"慕容美雪":(170,60,'賞花')}
f = open('美雪','w',encoding='utf-8')
json.dump(dic,f)  # 先接收要序列化的對象,再接收文件句柄
f.close()

執行程序,查看文件美雪內容爲:
{"\u6155\u5bb9\u7f8e\u96ea": [170, 60, "\u8d4f\u82b1"]}
要想文件寫入中文,能夠加參數ensure_ascii=False


import json  # 導入模塊
dic = {"慕容美雪":(170,60,'賞花')}
f = open('美雪','w',encoding='utf-8')
json.dump(dic,f,ensure_ascii=False)  # 先接收要序列化的對象,再接收文件句柄
f.close()

執行程序,再次查看文件內容:

{"慕容美雪": [170, 60, "賞花"]}

 
 
 load 讀取文件中的序列化內容

import json  # 導入模塊
dic = {"慕容美雪":(170,60,'賞花')}
f = open('美雪','r',encoding='utf-8')
ret = json.load(f)  #接收文件句柄
print(ret)  # 查看內容
print(type(ret))  # 查看變量類型
f.close()  # 最後記得關閉文件句柄

執行輸出:

{'慕容美雪': [170, 60, '賞花']}
<class 'dict'>

 其餘參數:

import json
data = {'username':['李華','二愣子'],'sex':'male','age':16}
json_dic2 = json.dumps(data,sort_keys=True,indent=4,separators=(',',':'),ensure_ascii=False)
print(json_dic2)

執行輸出:
{
    "age":16,
    "sex":"male",
    "username":[
        "李華",
        "二愣子"
    ]
}

參數說明:
    Skipkeys:默認值是False,若是dict的keys內的數據不是python的基本類型(str,unicode,int,long,float,bool,None),設置爲False時,就會報TypeError的錯誤。此時設置成True,則會跳過這類key 
    ensure_ascii:,當它爲True的時候,全部非ASCII碼字符顯示爲\uXXXX序列,只需在dump時將ensure_ascii設置爲False便可,此時存入json的中文便可正常顯示。)
    indent:應該是一個非負的整型,若是是0就是頂格分行顯示,若是爲空就是一行最緊湊顯示,不然會換行且按照indent的數值顯示前面的空白分行顯示,這樣打印出來的json數據也叫pretty-printed json 
    separators:分隔符,其實是(item_separator, dict_separator)的一個元組,默認的就是(',’,’:’);這表示dictionary內keys之間用","隔開,而KEY和value之間用":"隔開。
    sort_keys:將數據根據keys的值進行排序。 

寫入多行

import json
dic1 = {"S":(170,60,'唱歌')}
dic2 = {"H":(170,60,'唱歌')}
dic3 = {"E":(170,60,'唱歌')}
f = open('she','a',encoding='utf-8')
f.write(json.dumps(dic1)+'\n')  # 寫入一行內容,注意,必定要加換行符
f.write(json.dumps(dic2)+'\n')
f.write(json.dumps(dic3)+'\n')
f.close()  # 關閉文件句柄

執行程序,查看文件she內容:

{"S": [170, 60, "\u5531\u6b4c"]}
{"H": [170, 60, "\u5531\u6b4c"]}
{"E": [170, 60, "\u5531\u6b4c"]}

讀取多行

import json
f = open('she','r',encoding='utf-8')
for i in f:
    print(json.loads(i.strip()))
f.close()

執行輸出:

{'S': [170, 60, '唱歌']}
{'H': [170, 60, '唱歌']}
{'E': [170, 60, '唱歌']}

總結:

    dumps序列化 loads反序列化 只在內存中操做數據 主要用於網絡傳輸 和多個數據與文件打交道
  dump序列化 load反序列化 主要用於一個數據直接存在文件裏—— 直接和文件打交道

 


 

8、Pickle模塊 

  用於Python特有的類型和Python的數據類型間進行轉換 。 pickle模塊提供了四個功能:dumps、dump(序列化,存)、loads(反序列化,讀)、load(不只能夠序列化字典、列表……還能夠把Python中任意的數據類型序列化)

  用法和json是同樣的 :  注意的是Pickle模塊是基於字節操做,因此在讀寫的時候要用’wb‘和’rb'

dumps序列化:

import pickle
dic = {(170,60,'唱歌'):"S"}
print(pickle.dumps(dic))

#執行結果:
b'\x80\x03}q\x00K\xaaK<X\x06\x00\x00\x00\xe5\x94\xb1\xe6\xad\x8cq\x01\x87q\x02X\x01\x00\x00\x00Sq\x03s.'
輸出結果是bytes類型的,區別於json

dump寫入文件
文件模式必須是帶b,由於它是bytes類型、

import pickle
dic = {(170,60,'唱歌'):"S"}
f = open('s','wb') #使用dump必須以+b的形式打開文件,編碼不須要指定,由於是bytes類型
pickle.dump(dic,f)
f.close()  # 注意要關閉文件句柄

#執行結果是一堆亂碼

load 讀取文件內容:

import pickle
f = open('s','rb')  # bytes類型不須要指定編碼
print(pickle.load(f))
f.close()  # 注意要關閉文件句柄

執行結果:
{(170, 60, '唱歌'): 'S'}

dump寫入多行內容和load讀取文件內容:

import pickle
dic1 = {"張靚穎":(170,60,'唱歌')}
dic2 = {"張韶涵":(170,60,'唱歌')}
dic3 = {"梁靜茹":(170,60,'唱歌')}
f = open('singer','wb')
pickle.dump(dic1,f)
pickle.dump(dic2,f)
pickle.dump(dic3,f)
f.close()

#執行結果是一堆亂碼

load 讀取文件內容
import pickle
f = open('singer','rb')
print(pickle.load(f))
print(pickle.load(f))
print(pickle.load(f))
print(pickle.load(f))  # 多讀取一行,就會報錯
f.close()

可是輸出的結果以下

爲了解決這個問題,須要用到while循環+try:

import pickle
f = open('singer','rb')
while True:
    try:
        print(pickle.load(f))
    except Exception:  # 接收一切錯誤
        break  # 跳出循環
f.close()

執行結果:
{'張靚穎': (170, 60, '唱歌')}
{'張韶涵': (170, 60, '唱歌')}
{'梁靜茹': (170, 60, '唱歌')}

總結:

json  在寫入屢次dump的時候 不能對應執行屢次load來取出數據,pickle能夠
json  若是要寫入多個元素 能夠先將元素dumps序列化,f.write(序列化+'\n')寫入文件
    讀出元素的時候,應該先按行讀文件,在使用loads將讀出來的字符串轉換成對應的數據類型

 

注意:pickle還能夠序列化一些類或者函數(json不能):

import pickle
class A:
    def __init__(self,name,age):
        self.name=name
        self.age=age
a = A('alex',80)
ret = pickle.dumps(a)  # 序列化對象
print(ret)
obj = pickle.loads(ret)  # 反序列化
print(obj.__dict__)  # 查看對象屬性<br>f.close()

執行結果:
b'\x80\x03c__main__\nA\nq\x00)\x81q\x01}q\x02(X\x04\x00\x00\x00nameq\x03X\x04\x00\x00\x00alexq\x04X\x03\x00\x00\x00ageq\x05KPub.'
{'name': 'alex', 'age': 80}


將對象a寫入文件:
import pickle
class A:
    def __init__(self,name,age):
        self.name=name
        self.age=age
a = A('alex',80)
f = open('a','wb')
obj = pickle.dump(a,f)
f.close()

執行結果:
也是一堆亂碼

  假設是一款Python遊戲,就能夠將人物的屬性,寫入文件。再次登錄時,就能夠從新加載了,用pickle就比較方便了。

當刪除一個類的時候(註釋代碼),再次讀取文件,就會報錯

import pickle
# class A:
#     def __init__(self,name,age):
#         self.name=name
#         self.age=age
# a = A('alex',80)
f = open('a','rb')
obj = pickle.load(f)
print(obj.__dict__)
f.close()

執行報錯

AttributeError: Can't get attribute 'A' on <module '__main__' from 'E:/python_script/day25/test.py'>
提示找不到類A

 

  將對象反序列時,必須保證該對象的類必須存在,不然讀取報錯

  再次打開註釋,執行如下,就正常了


 

9、shelve模塊

   Shelve是對象持久化保存方法,將對象保存到文件裏面,缺省(即默認)的數據存儲文件是二進制的。能夠做爲一個簡單的數據存儲方案。

注意shelve模塊中的key鍵必須是字符串形式,value能夠是任意值。會同時打開三個文件。

  使用方法: 

  一、shelve.open(filename, flag=’c’, protocol=None, writeback=False):      建立或打開一個shelve對象。shelve默認打開方式支持同時讀寫操做。

    filename是關聯的文件路徑。
  可選參數flag:
    一、默認爲‘c’:若是數據文件不存在,就建立,容許讀寫;能夠是: ‘r’: 只讀;’w’: 可讀寫;
    二、能夠爲‘n’: 每次調用open()都從新建立一個空的文件,可讀寫

  protocol:是序列化模式,默認值爲None。具體尚未嘗試過,從pickle的資料中查到如下信息【protocol的值能夠是1或2,表示以二進制的形式序列化】

  二、shelve.close()      # 同步並關閉shelve對象,注意每次使用完畢後都要關閉shelve對象,一樣可使用with語句。

with shelve.open('spam') as db:
    db['eggs'] = 'eggs'
with語句

  三、writeback:默認爲False。當設置爲True之後,shelf將會將全部從DB中讀取的對象存放到一個內存緩存。

當咱們close()打開的shelf的時候,緩存中全部的對象會被從新寫入DB。writeback方式有優勢也有缺點(減小出錯率,可是會增長內存開銷)。

代碼示範:

# 1.建立一個shelf對象,直接使用open函數便可

import shelve
s = shelve.open('test_shelf.db')         #
try:
    s['kk'] = {'int': 10, 'float': 9.5, 'String': 'Sample data'}
    s['MM'] = [1, 2, 3]
finally:
    s.close()

# 2.若是想要再次訪問這個shelf,只須要再次shelve.open()就能夠了,而後咱們能夠像使用字典同樣來使用這個shelf

import shelve
try:
    s = shelve.open('test_shelf.db')
    value = s['kk']
    print(value)
finally:
    s.close()

# 3.對shelf對象,增、刪、改操做

import shelve
s = shelve.open('test_shelf.db', flag='w', writeback=True)
try:
    # 增長
    s['QQQ'] = 2333
    # 刪除
    del s['MM']
    # 修改
    s['kk'] = {'String': 'day day up'}
finally:
    s.close()

# 注意:flag設置爲‘r’-只讀模式,當程序試圖去修改一個以只讀方式打開的DB時,將會拋一個訪問錯誤的異常。異常的具體類型取決於anydbm這個模塊在建立DB時所選用的DB。異常舉例:anydbm.error: need ‘c’ or ‘n’ flag to open new db

# 4.循環遍歷shelf對象

import shelve
s = shelve.open('test_shelf.db')
try:
    # 方法一:
    for item in s.items():
        print ('鍵[{}] = 值[{}]'.format(item[0], s[item[0]]))
    # 方法二:
    for key, value in s.items():
        print(key, value)
finally:
    s.close()

# 5.備註一個錯誤:
# open中的參數filename,起初認爲須要手動新建一個.db,或者.dat的文件,目前電腦中無任何真正的數據庫文件,因此採用了新建txt文件,修改後綴的方法建立.db,或者.dat的文件。
# 解釋器報錯,提示內容爲:"anydbm.error: db type could not be determined",
# 緣由是是filename已經存在,而且格式與shelve不符,因此提示 「db type could not be determined」。
# 解決方法是,刪除該文件。首次運行後會自動生成該filename文件。
# 6.稍微複雜些的案例,實現一個簡單提問式的數據庫
shelve模塊代碼示例

 

總結: 

 一、shelve模塊比pickle模塊簡單,只有一個open函數,返回相似字典的對象,可讀可寫;
 二、key必須爲字符串,而值能夠是python所支持的數據類型
 三、shelve模塊(**)------能夠當作數據庫用,之後基本不會用,(能夠很方面的往文件中寫數據類型和讀)
import shelve             #存取很方便(能夠作一個簡單的數據存儲方案)
f=shelve.open(r'sheve.txt')
f['stu1_info']={'name':'egon','age':18,'hobby':['piao','smoking','drinking']}   #存
f['stu2_info']={'name':'gangdan','age':53}
f['school_info']={'website':'http://www.pypy.org','city':'beijing'}
print(f['stu1_info']['hobby'])
f.close()
 
import shelve
d=shelve.open(r'a.txt')                   #生成三個文件分別是:a.txt.bak\a.txt.dat\a.txt.dir
d['tom']={'age':18,'sex':'male'}         #存的時候會生成三個文件,不用管,是python的一種處理機制
print(d['tom']['sex'])                   #能夠取出字典中的key對應的value
print(d['tom'])                          #取出tom對應的字典
d.close()

import shelve
d=shelve.open(r'a.txt',writeback=True)    #writeback=True,對子字典修改完後要寫回,不然不會看到修改後的結果
d['egon']={'age':18,'sex':'male'}         #存的時候會生成三個文件,不用管,是python的一種處理機制
d['egon']['age']=20                       #將年齡修改成20
print(d['egon']['age'])                   #此時拿到的是修改後的年齡
print(d['egon']['sex'])
d.close()
相關文章
相關標籤/搜索