1. 程式人生 > 實用技巧 >17Python學習之常用內建模組

17Python學習之常用內建模組

常用內建模組

os 模組

os的檔案操作

remove()

remove是刪除檔案的命令,需要一個引數,如果傳入的是一個路徑,報 IsADirectoryError 錯誤

語法:

remove(file_path)

例1:

import os

os.remove('/tmp/a.txt')

rename()

rename既能修改檔名,也能修改目錄名,需要兩個引數,第一個是原檔名,第二個是目標檔名。 修改檔名不會改變檔案中的內容。

語法:

rename(src, dst)

注意:

如果目標檔名存在:

在Linux系統中,會直接覆蓋。報 OSError (目標檔案存在時) 或 FileExistsError

(原始檔不存在時)錯誤

例1:

# 建立檔案和目錄
mkdir -p /tmp/dir1/dir2		# 建立目錄
touch /tmp/dir1/a.txt		# 建立檔案
echo "This is a test file in old_file named a.txt" >> /tmp/dir1/a.txt	# 向檔案寫入內容

結果是:

/tmp
└── dir1
├── a.txt
└── dir2

import os

os.rename('/tmp/dir1', '/tmp/dir')             # 給目錄改名
os.rename('/tmp/dir/a.txt', '/tmp/dir/test.txt')    # 在改名後的目錄中修改檔名

執行結果:

/tmp
└── dir
├── dir2
└── test.txt

rmdir()

rmdir是刪除目錄,如果目錄不為空,將報 OSError (非空報錯)或 FileNotFoundError (不存在報錯)錯誤

語法:

rmdir(path)

例1:

建立目錄

mkdir /tmp/dir1				# 建立目錄
touch /tmp/dir1/a.txt		# 目錄中建立檔案,使目錄不為空
tree						# tree檢視結果,返回樹狀結構

/tmp
└── dir1
└── a.txt

import os

os.rmdir('/tmp/dir1')

執行結果:

Traceback (most recent call last):
File "/projects/oldboy/laptop/day09/test_file.py", line 6, in
os.rmdir('/tmp/dir1')
OSError: [Errno 39] Directory not empty: '/tmp/dir1'

removedirs()

removedirs也是刪除目錄,跟rmdir的區別是,如果層級目錄都是空,removedirs會逐層刪除空目錄。

語法:

removedirs(path)

例1:

# 建立目錄結構
mkdir -p /tmp/dir1/dir2/dir3/dir4
touch /tmp/dir1/dir2/a.txt
tree									# 用tree檢視結果

結果如下:

/tmp

└── dir1
└── dir2
├── a.txt
└── dir3
└── dir4

import os

os.removedirs('/tmp/dir1/dir2/dir3/dir4')

執行結果:

└── dir1
└── dir2
└── a.txt

說明:

由於dir4刪除後dir3也是一個空目錄,removedirs會繼續刪除空目錄,直到dir2,裡面有個a.txt目錄不為空,如果dir2也是空,會繼續刪除下去。而rmdir只會刪除dir4,這是removedirs和rmdir最明顯的區別

rmtree()

上面兩個刪除目錄的方法,無法刪除非空目錄。rmtree方法可以刪除非空目錄,這個方法位於 shutil 模組中,要使用該方法需要先匯入模組

語法:

rmtree(path)

例1:

mkdir -p /tmp/dir1/dir2/dir3/dir4
touch /tmp/dir1/dir2/dir3/dir4/a.txt
tree									# 用tree檢視結果

執行結果:

/tmp/
└── dir1
└── dir2
└── dir3
└── dir4
└── a.txt

import os
import shutil

# os.rmdir('/tmp/dir1/dir2')			# 報錯:OSError
shutil.rmtree('/tmp/dir1/dir2')			# 正常刪除

執行結果:

/tmp/
└── dir1

os的路徑操作

os的路徑操作在子模組中,即os.path模組中

dirname()

dirname返回傳入的path中的路徑名,並不會驗證路徑和檔案是否存在

例1:

import os

ret = os.path.dirname('/tmp/dir1/dir2/a.txt')
print(ret)

執行結果:

/tmp/dir1/dir2

basename()

basename 返回給定路徑中的檔名,同dirname一樣,也不會考慮檔案或路徑是否存在,只管返回檔名,如果路徑以斜線結尾,那麼將返回空

例1:

import os

ret = os.path.basename('/tmp/dir1/dir2/a.txt')
print(ret)

執行結果:

a.txt

split()

split 以元組的形式返回路徑名和檔名,不考慮路徑是否有效

例1:

import os

ret = os.path.split('/tmp/dir1/dir2/a.txt')
print(ret)

執行結果:

('/tmp/dir1/dir2', 'a.txt')

splittext()

splittext 同split一樣也是返回一個元組,區別在於,splittext 返回的元組中以英文的句號為分隔,相當於返回的是檔案的字尾名。句點搜尋從右往左,如果沒有返回空

例1:

import os

my_path = '/tmp/dir1/dir2/a.txt'
ret = os.path.split(my_path)
print('split返回:', ret)

ret1 = os.path.splitext(my_path)
print('splitext返回', ret1)

執行結果:

split返回: ('/tmp/dir1/dir2', 'a.txt')
splitext返回 ('/tmp/dir1/dir2/a', '.txt') # 返回的相當於是字尾名

isdir()

isdir判斷給出的路徑是不是目錄,只有路徑真實存在並且是目錄的時候才返回True,否則都是False,如果是軟連線,該軟連線指向的也是目錄,返回的結果也是True

例1:

mkdir /tmp/dir1					# 建立目錄
touch /tmp/dir1/a.txt			# 建立檔案
ln -s /tmp/dir1 /test			# 建立軟連線
import os

mypath = '/tmp/dir1/a.txt'			# 不是目錄是一個檔案的路徑
ret = os.path.isdir(mypath)
print(ret)

mypath2 = '/test'
ret2 = os.path.isdir(mypath2)
print(ret2)

執行結果:

Fasle

True

isfile()

判斷給出的路徑是不是一個檔案

判斷給出的路徑是不是一個軟連線

exists()

判斷一個檔案或目錄是否存在,存在返回True,否則返回False

import os

mypath = '/tmp/dir1/a.txt'
ret = os.path.exists(mypath)
print(ret)

執行結果:

True

sys 模組

argv()

argv是一個列表,該列表儲存的是從命令列指向程式碼時傳入的引數, 第一個引數預設是檔名。

例1:

import sys

for idx, value in enumerate(sys.argv):
    print(f'第 { idx } 個引數是:{value}')

執行方式:

python3 /projects/sysdemo.py  你好 數學 英語

執行結果:

第 0 個引數是:/projects/sysdemo.py
第 1 個引數是:你好
第 2 個引數是:數學
第 3 個引數是:英語

exit()

exit 是一個退出函式,他有一個引數 status 指明是按照什麼狀態退出的,預設是None 他跟 0 是一個意思,說明是正常退出的,status的取值範圍是 0 - 127,這個退出狀態在Linux中表現為 echo $? 顯示的狀態碼,有時候可以幫助我們查詢異常退出的情況

例1:

import sys

try:
    num = int(input('請輸入一個整數:'))
except ValueError:
    # 我們定義資料轉換異常就丟擲錯誤程式碼為 15
    sys.exit(15)

執行方式:

python3 /projects/sysdemo.py
請輸入一個整數: a					# 提示我們輸入整數,但我們輸入了一個字母
echo $?							# $? 打印出退出碼

執行結果:

15

getwindowsversion()

獲取Windows系統的版本資訊, 僅支援在Windows系統上執行 ,他的返回值是一個列表

例1:

import sys

print(sys.getwindowsversion())			

path()

path是Python直譯器的查詢路徑,他是一個列表,Python直譯器會在列表中的目錄下去查詢相應的模組資訊,如果我們有自定義的模組路徑,可以通過append加入該列表

例1:

import sys

print(sys.path)

paltform屬性

這是一個屬性,不是方法,我們可以通過他獲取當前程式執行的平臺,然後我們可以針對不同的平臺執行對應的程式

對應平臺如下:

平臺 對應程式碼
AIX 'aix'
Linux 'linux'
Windows 'win32'
Windows/Cygwin 'cygwin'
macOS 'darwin'

例1:

import sys

ret = sys.platform
if ret.startswith('linux'):
    print('這是Linux平臺')
elif ret.startswith('win32'):
    print('這是Windows平臺')

在Linux下執行的結果:

這是Linux平臺

在Windows下執行的結果:

這是Windows平臺

time 模組

time提供了與時間相關的一些函式

time模組常用的方法有:

time()

time()返回從 1970-01-01 00:00:00 秒到當前時間經過的秒數

例1:

import time

ret = time.time()
print(ret)

執行結果:

1596771508.143643

gmtime()

該方法有一個引數,輸入相應的描述,會給出具體的時間物件

gmtime() 返回格林尼治時間,該方法返回的是一個time型別的結構化時間物件,我們可以使用下標或者屬性名將值取出來

下標 屬性名 說 明 值範圍
0 tm_year 年份 2020
1 tm_mon 月份 1-12
2 tm_mday 1-31
3 tm_hour 0-23
4 tm_min 0-59
5 tm_sec 0-61,因為涉及到閏秒,可檢視文件
6 tm_wday 星期幾 0-6,週一是0
7 tm_yday 一年中的第幾天 0-366
8 tm_isdst 夏令時 0,1或-1,夏令時為1, 否則為0,-1表示未知
無索引 tm_zone 時區名縮寫 /
無索引 tm_gmtoff 以秒為單位向UTC東時區偏移 /

例1:

import time

ret = time.gmtime()
print(ret)
print(type(ret))
print('年份是:', ret[0])           # 下標方式取年份
print('月份是:', ret.tm_mon)       # 屬性方式取月份

執行結果:

time.struct_time(tm_year=2020, tm_mon=8, tm_mday=7, tm_hour=3, tm_min=51, tm_sec=24, tm_wday=4, tm_yday=220, tm_isdst=0)
<class 'time.struct_time'>
年份是: 2020
月份是: 8

例2:

import time

ret = time.gmtime(1297879384)
print(ret)
print(f'給定的秒數是:{ret.tm_year} 年 {ret.tm_mon} 月 {ret.tm_mday} 日 '
      f'{ret.tm_hour}:{ret.tm_min}:{ret.tm_sec} 星期{ret.tm_wday + 1}')

執行結果:

time.struct_time(tm_year=2011, tm_mon=2, tm_mday=16, tm_hour=18, tm_min=3, tm_sec=4, tm_wday=2, tm_yday=47, tm_isdst=0)
給定的秒數是:2011年 2 月 16 日 18:3:4 星期3

localtime()

該方法有一個引數,輸入相應的描述,會給出具體的時間物件

獲取本地時間,用法跟gmtime()一樣,只是 用的是本地時區

import time

ret = time.localtime()		# 中國是東八區,用gmtime() hour 需要加8,localtime不需要
print(ret)
print(type(ret))
print('年份是:', ret[0])           # 下標方式取年份
print('月份是:', ret.tm_mon)       # 屬性方式取月份

執行結果:

time.struct_time(tm_year=2020, tm_mon=8, tm_mday=7, tm_hour=12, tm_min=10, tm_sec=26, tm_wday=4, tm_yday=220, tm_isdst=0)
<class 'time.struct_time'>
年份是: 2020
月份是: 8

strftime()

strftime()是格式化時間戳,將時間戳轉換成易讀的格式

語法:

strftime(格式 [, 時間物件])

注意:

時間物件可選,如果時間物件沒有,預設是 localtime() 獲取的時間戳

佔位符 說明
%a 當前地區的星期縮寫
%A 當前地區的星期全稱
%b 當前地區月份的縮寫
%B 當前地區月份的全稱
%p 12小時制,大寫方式顯示上午(AM),下午(PM)
%U 顯示當前為一年中的第幾周,以星期天為每週的第一天
%W 顯示當前為一年中的第幾周,以星期一為每週的第一天
%w 以數字的形式顯示,星期中的第幾天(0-6,星期天是0)
%y 年:兩位數的方式表示年份
%Y 年:完整的四位數表示年份
%m 月:以兩位數顯示
%d 日:以兩位數顯示
%H 時:24小時制,以兩位數顯示
%I 時:12小時制,以兩位數顯示
%M 分:以兩位數顯示
%S 秒:以兩位數顯示
%z 顯示當前的時區(東八區:+0800)
%% 顯示一個百分號,轉義

例1:

import time

ret = time.strftime('%Y-%m-%d %H:%M:%S')
print(ret)

執行結果:

2020-08-07 13:49:21

strptime()

將易讀的時間,解析成時間物件,時間字串和格式化的格式必須完全一致,否則會報 ValueError 錯誤

語法:

strptime(時間字串, 格式)

例1:

import time

time_str = '2020-08-07 14:52:32'
# time_str = '2020/08/07 14:52:32'			報錯,因為年月日的分隔符不匹配
ret = time.strptime(time_str, '%Y-%m-%d %H:%M:%S')	# 格式必須跟time_str中的格式和分隔符一樣
print(ret)

執行結果:

time.struct_time(tm_year=2020, tm_mon=8, tm_mday=7, tm_hour=14, tm_min=52, tm_sec=32, tm_wday=4, tm_yday=220, tm_isdst=-1)

datetime模組

date類

date類中是日期相關的內容,date類只處理年月日

該類需要三個初始化引數 year, month, day

語法:

datetime.date(year, month, day)

說明:

三個引數的取值範圍如下,如果有一個超出了範圍,報 ValueError 錯誤

1 <= year <= 9999
1 <= month <=12
1<= day <= 給定月份在年份中的天數

例1:

import datetime

ret = datetime.date(2020, 8, 7)
print(ret)

執行結果:

2020-08-07

常用函式:

方法 說明
方法
today() 獲取當前日期
fromtimestamp(timestamp) 將時間戳轉換成日期
fromordinal(days) 返回給定天數是從1年1月1日經過days天的日期,它和 toordinal 函式正好相反
toordinal() 將一個日期轉換成從1年1月1日開始的天數,它和 fromordinal 函式正好相反
fromisoformat(date_string) 將一個給定的字串格式的日期,轉換成日期物件,字串格式必須是:YYYY-mm-dd, 3.7版本及以上才支援
fromisocalendar(year, week, day) 給一個日曆的,年,周和天,返回該位置的日期, 周[1-53],天[1-7], 3.8版本及以上才支援
屬性
year 獲取date物件中的年
month 獲取date物件中的月
day 獲取date物件中的日
resolution 跟datedelta計算的最小單位即:days=1

例2:

import datetime

print('today方法:', datetime.date.today())
print('fromtimestamp方法:', datetime.date.fromtimestamp(1596788844))
print('toordinal方法:', datetime.date.toordinal(datetime.date.today()))
print('fromordinal方法:', datetime.date.fromordinal(737644))

ret = datetime.date.today()
print('當前年份是:', ret.year)
print('當前月份是:', ret.month)
print('當前日期是:', ret.day)

執行結果:

today方法: 2020-08-07
fromtimestamp方法: 2020-08-07
toordinal方法: 737644
fromordinal方法: 2020-08-07
當前年份是: 2020
當前月份是: 8
當前日期是: 7

time類

time類中是時間,time類中只處理:時、分、秒、微秒、毫秒和時區

語法:

datetim.time(hour, minute, microsecond, tzinfo=None)

說明:

引數的取值範圍如下,如果超出了範圍,報 ValueError 錯誤

0 <= hour <= 24
0 <= minute< 60
0 <= minute< 60
0 <= microsecond < 1000000

常用函式:

方法 說明
isoformat(timespec='auto') 指定顯示的最小單位:
預設是auto,精確到微秒;
hours,精確到小時;
minutes,精確到分鐘;
seconds,精確到秒
strftime(format_string) 按給定的格式輸出時間

例1:

from datetime import time

ret = time(17, 27, 18, 200)
print('時間物件:', ret)
print('時:', ret.hour)
print('分:', ret.minute)
print('秒:', ret.second)
print('微秒:', ret.microsecond)
print('不指定單位:', ret.isoformat())                       # 不指定預設是auto,精確到為秒
print('指定最小單位為時:', ret.isoformat(timespec='hours'))  # 指定顯示最小單位為小時
print('指定顯示最小單位為分:', ret.isoformat(timespec='minutes'))  # 指定顯示最小單位為分鐘
print('指定顯示最小單位為秒:', ret.isoformat(timespec='seconds'))  # 指定顯示最小單位為秒
print(ret.strftime('%H 時 %M 分 %S 秒'))

執行結果:

時間物件: 17:27:18.000200
時: 17
分: 27
秒: 18
微秒: 200
不指定單位: 17:27:18.000200
指定最小單位為時: 17
指定顯示最小單位為分: 17:27
指定顯示最小單位為秒: 17:27:18
17 時 27 分 18 秒

datetime類

datetime類中是日期和時間,相當於整合了date和time

語法:

datetime(year, month, day, hour, minute, second, microsecond)

說明:

引數的取值範圍如下:

MINYEAR <= year <= MAXYEAR,
1 <= month <= 12,
1 <= day <= number of days in the given month and year,
0 <= hour < 24,
0 <= minute < 60,
0 <= second < 60,
0 <= microsecond < 1000000,

常用函式:

方法 說明
today() 獲取當前時間包含時區tzinfo
now() 獲取當前時間不包含時區
fromtimestamp() 將時間戳轉換成日期
timestamp() 將日期轉換成時間戳
strftime() 格式化日期
strptime() 解析日期
date() 獲取日期
time() 獲取時間

例1:

from datetime import datetime

print('獲取時間', datetime.today())
print('獲取時間:', datetime.now())
print('將時間戳轉換成日期:', datetime.fromtimestamp(1596788844))
print('將日期轉換成時間戳:', datetime.now().timestamp())
print('格式化日期:', datetime.now().strftime('%Y年 %m月 %d日  %H時 %M分 %S秒'))
print('日期解析:', datetime.strptime('2020年 08月 07日  18時 09分 56秒', '%Y年 %m月 %d日  %H時 %M分 %S秒'))
print('獲取日期:', datetime.today().date())
print('獲取時間:', datetime.today().time().isoformat(timespec='seconds'))
print('返回日期和時間的字串:', datetime.today().isoformat(sep=' ', timespec='seconds'))

執行結果:

獲取時間 2020-08-07 18:10:43.937599
獲取時間: 2020-08-07 18:10:43.937662
將時間戳轉換成日期: 2020-08-07 16:27:24
將日期轉換成時間戳: 1596795043.93768
格式化日期: 2020年 08月 07日 18時 10分 43秒
日期解析: 2020-08-07 18:09:56
獲取日期: 2020-08-07
獲取時間: 18:10:43
返回日期和時間的字串: 2020-08-07 18:10:43

timedelta類

timedelta類是一個時間變化量,可以跟一個日期和日期時間物件進行數學計算,從而獲得需要的新時間

注意:

timedelta只能和date、datetime、timedelta進行數學計算, 不能和time進行計算

語法:

timedelta(weeks, days, hours, minutes, seconds, microsecons, milliseconds)

說明:

0 <= microseconds < 1000000
0 <= seconds < 3600*24 (the number of seconds in one day)
-999999999 <= days <= 999999999

支援的操作有(詳見官方文件):

+、-、*、/、//、%、divmod

例1:

import datetime

mydate = datetime.date.today()      # 獲取當前日期
delta1 = datetime.timedelta(days=10) # 初始化 timedelta
print('加之前:', mydate)
mydate += delta1
print('加之後:', mydate)

mydatetime = datetime.datetime.now()
delta2 = datetime.timedelta(hours=2, minutes=10) # 初始化 timedelta
print('加之前:', mydatetime)
mydatetime += delta2     # 加10天零8小時10分鐘
print('加之前:', mydatetime)

delta3 = delta1 + delta2
print('delta相加:', delta3)

mytime = datetime.datetime.now().time()
# mytime += delta2          # 報錯,不支援這樣的操作
print('時間是:', mytime)

執行結果:

加之前: 2020-08-07
加之後: 2020-08-17
加之前: 2020-08-07 18:28:54.503255
加之前: 2020-08-07 20:38:54.503255
delta相加: 10 days, 2:10:00
時間是: 18:28:54.503284

random模組

此模組提供了和隨機數相關的方法(random是偽隨機數)。在模組內部,使用了將方法賦值給了屬性的方式,比如:randrange 是一個屬性,在模組內部定義了將Random類的方法賦值給了randrange,因此randrange實際指向的是randrange方法。

randrange內部實現如下:

_inst = Random()
randrange = _inst.randrange

random模組常用方法有:

random.random()

獲取 [0.0, 1.0) 之間的浮點數

例1:

import random

print(random.random())

執行結果:

0.25784570611056934

random.randint(a, b)

返回一個在 [a, b] 之間的整數N, 包含a 或 b

例1:

import random

print(random.randint(1, 5))

執行結果:

3

random.uniform(a, b)

返回一個 [a,b]或[a,b) 之間的浮點數(a,b大小順序不限)

例1:

import random

print(random.uniform(10, 5))

執行結果:

6.314250748038026

random.shuffle()

將一個有序的可變資料型別,打亂,無返回值,改變的是可迭代物件本身

例1:

import random

li = list(range(10))
print(li)
random.shuffle(li)
print(li)

執行結果:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[2, 8, 3, 5, 1, 7, 6, 9, 0, 4]

random.smaple(iter, x)

從一個可雜湊的序列或集合中,返回長度為x的一個列表,如果x的長度大於序列或集合,會報 ValueError 錯誤。如果序列中的元素有重複,那麼返回的列表中元素也可能會重複

例1:

import random

li = list(range(10))
print(li)
ret = random.sample(li, 5)
print(ret)

執行結果:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[3, 0, 7, 8, 5]

例2:

import random

li = [1, 2, 3, 4, 5, 6, 7, 2, 1, 5, 7]			# 元素重複
print(li)
ret = random.sample(li, 5)
print(ret)

執行結果:

[1, 2, 3, 4, 5, 6, 7, 2, 1, 5, 7]
[2, 4, 3, 1, 2] # 2 重複獲得

random.randrange()

返回一個指定範圍內的隨機數,randrange有三個引數,start和step可以省略,start指定隨機數的開始,stop指定隨機數的結束位置,step指定步長

例1:

import random

ret = random.randrange(1, 101, 2)			# 返回奇數的隨機數
print('1~100之間的奇數隨機數:', ret)

執行結果:

3

json模組和pickle模組

json模組

json是JavaScript Object Notation的縮寫,即java指令碼兌換標記語言,已經成為一種簡單的資料交換格式,在Python中,只有集合(set)不能用json表示

序列化:將記憶體中的結構化資料,轉換成位元組傳,用以儲存在檔案或者通過網路傳輸稱為線性化過程

反序列化: 從檔案或網路中獲取的資料,轉換成記憶體中原來的資料型別稱為返序列化過程

json將資料轉換成字串,用於儲存或網路傳輸,由於並未轉換成位元組串,所以不太徹底

dumps()

dumps是將記憶體中的結構化資料進行序列號,即將結構化資料轉換成字串,dumps是從記憶體到記憶體,而dump是從記憶體到檔案

例1:

import json

li = [1, 2, 3, 4]
ret = json.dumps(li)        # dumps將結構化資料轉換成字串
print(type(ret))
print('%r' % ret)           # 用原始格式顯示

tu = (1, 2, 3, 4)
ret = json.dumps(tu)        # 元組轉換後變成了列表的格式,圓括號變成了方括號
print(type(ret))
print('%r' % ret)           # 用原始格式顯示

執行結果:

<class 'str'>
'[1, 2, 3, 4]'

<class 'str'>
'[1, 2, 3, 4]'

loads()

loads是將從檔案或網路中獲取的資料,轉化為結構化資料,即反序列化。loads是從記憶體到記憶體,load是從檔案到記憶體

import json

li = [1, 2, 3, 4]
ret = json.dumps(li)        # ret是序列化後的字串
print('dumps的結果是:%r, 型別是:%s' % (ret, type(ret)))
res = json.loads(ret)       # 進行反序列號
print('loads的結果是:%r, 型別是:%s' % (res, type(res)))

執行結果:

dumps的結果是:'[1, 2, 3, 4]', 型別是:<class 'str'>
loads的結果是:[1, 2, 3, 4], 型別是:<class 'list'>

dump 和load

dump和load的作用域上面dumps和loads一樣,區別在於,dump和load是轉換成流,寫入檔案和從檔案中讀取json。 dump和load都一次性儲存和讀取,如果需要多次,直接用檔案的write和read模式

例1:

import json

li = [1, 2, 3, 4]
with open('ret.txt', mode='a+', encoding='utf-8') as f:
    json.dump(li, f)

# 讀取
with open('ret.txt', mode='r', encoding='utf-8') as f:
    ret = json.load(f)
    print(ret)

執行結果:

[1, 2, 3, 4]

例2:

import json

li = [1, 2, 3, 4]
with open('ret.txt', mode='a+', encoding='utf-8') as f:
    f.write(json.dumps(li) + '\n')		# 利用write和dumps

# 讀取
with open('ret.txt', mode='r', encoding='utf-8') as f:
    for i in f.readlines():
        ret = json.loads(i.strip())		# 利用read和loads
        print(ret)

執行結果:

[1, 2, 3, 4]
[1, 2, 3, 4]

pickle模組

pickle的用法跟json一樣,有四個方法dump、dumps、load、loads,它能處理Python中的所有資料型別包括集合set,

將Python中所有的資料型別轉換成 位元組串 ,序列化過程

將位元組串轉換成Python中資料型別,反序列化過程。

json和pickle 的區別:

  1. pickle所有型別都可以序列化,結果是位元組串
  2. pickle的dump和load自帶多次寫和多次讀。
  3. pickle不能跨語言,只能針對Python語言。
  4. dumps前是什麼型別,loads後還是什麼型別,型別不變

例1:

import pickle

li = [1, 2, 3, 4]
ret1 = pickle.dumps(li)  # 轉換成pickle位元組串
print('dumps後的型別是:', type(ret1))
print('dumps後的結果是:', ret1)

tu = (1, 2, 3, 4)
ret2 = pickle.dumps(tu)  # 轉換成pickle位元組串
print('dumps後的型別是:', type(ret2))
print('dumps後的結果是:', ret2)

se = {1, 2, 3, 4}
ret3 = pickle.dumps(se)  # 轉換成pickle位元組串
print('dumps後的型別是:', type(ret3))
print('dumps後的結果是:', ret3)

# 反序列化
res1 = pickle.loads(ret1)
res2 = pickle.loads(ret2)
res3 = pickle.loads(ret3)
print('loads後的結果是:', res1)
print('loads後的結果是:', res2)
print('loads後的結果是:', res3)

執行結果:

dumps後的型別是: <class 'bytes'>
dumps後的結果是: b'\x80\x03]q\x00(K\x01K\x02K\x03K\x04e.'
dumps後的型別是: <class 'bytes'>
dumps後的結果是: b'\x80\x03(K\x01K\x02K\x03K\x04tq\x00.'
dumps後的型別是: <class 'bytes'>
dumps後的結果是: b'\x80\x03cbuiltins\nset\nq\x00]q\x01(K\x01K\x02K\x03K\x04e\x85q\x02Rq\x03.'
loads後的結果是: [1, 2, 3, 4]
loads後的結果是: (1, 2, 3, 4)
loads後的結果是: {1, 2, 3, 4}

例2:

import pickle

with open('ret.txt', mode='wb') as f:
    se = {1, 2, 3, 4}
    tu = (1, 2, 3, 4)
    li = [1, 2, 3, 4]
    dic = {'1': 1, '2': 2, '3': 3, '4': 4}
    pickle.dump(se, f)
    pickle.dump(tu, f)
    pickle.dump(li, f)
    pickle.dump(dic, f)


with open('ret.txt', mode='rb') as r:
    res1 = pickle.load(r)
    res2 = pickle.load(r)
    res3 = pickle.load(r)
    res4 = pickle.load(r)
    print(res1)
    print(res2)
    print(res3)
    print(res4)

執行結果:

{1, 2, 3, 4}
(1, 2, 3, 4)
[1, 2, 3, 4]
{'1': 1, '2': 2, '3': 3, '4': 4}

hashlib模組

hashlib封裝了一些用於加密的類,如:md5, sha1, sha512,可用 print(dir(hashlib)) 檢視所有加密方法

加密的目的:用於判斷和驗證,而並非解密

特點:

  1. 把一個大的資料,切分成不同塊,分別對不同的塊進行加密,再彙總的結果,和直接對整體資料加密的結果是一致的
  2. 單向加密,不可逆
  3. 原始資料的一點小的變化,將導致結果的差異非常大

加密分為三個步驟:

  1. 獲取加密物件
  2. 呼叫加密物件的update方法,進行加密
  3. 通過hexdigest方法獲取加密結果

不管用那種加密方式,都是上面三個步驟

例1:

import hashlib

# 獲取一個md5加密物件
md5_object = hashlib.md5()
# 呼叫update方法進行加密,引數必須是bytes型別
md5_object.update('md5加密'.encode())
# 利用hexdigest獲取加密結果
ret = md5_object.hexdigest()
print('md5加密結果是:', ret)

執行結果:

md5加密結果是: a3c9c2fe682a79e3b1703f001ba245a9

例2:

import hashlib

# 分塊加密
md5_object = hashlib.md5()
md5_object.update('我愛'.encode())
md5_object.update('我的祖國'.encode())
ret = md5_object.hexdigest()
print('分塊加密結果是:', ret)

# 未分塊加密
md5_object2 = hashlib.md5()
md5_object2.update('我愛我的祖國'.encode())
ret2 = md5_object2.hexdigest()
print('未分塊加密結果是:', ret2)

執行結果:

分塊加密結果是: e83482ae91900eadbc2384fc92ac6c98
未分塊加密結果是: e83482ae91900eadbc2384fc92ac6c98

例3:

利用加密實現註冊和登入驗證

import hashlib


# 註冊將使用者名稱和密碼寫入檔案
def regist(username, pwd):
    if username != '' and pwd != '':
        ret = get_encryption(username, pwd)
        with open('pwd.txt', mode='at', encoding='utf-8') as p, open('users.txt', mode='at', encoding='utf-8') as u:
            u.write(username + '\n')
            p.write(ret + '\n')
        return True
    else:
        return False


# 登入從檔案讀取使用者名稱和密碼並校驗
def login(username, pwd):
    if username != '' and pwd != '':
        with open('pwd.txt', mode='rt', encoding='utf-8') as p, open('users.txt', mode='rt', encoding='utf-8') as u:
            # 校驗使用者名稱
            for name in u.readlines():
                # 需要strip清除後面的換行符或空格
                if name.strip() == username.strip():
                    # 校驗密碼
                    for passwd in p.readlines():
                        # 需要strip清除後面的換行符或空格再比較,因為儲存的時候加了回車符號
                        if passwd.strip() == get_encryption(username.strip(), pwd.strip()):
                            return True
            # 如果使用者名稱不對,返回False,不驗證密碼
            else:
                return False


# 獲取加密密碼資訊,並返回加密資訊
def get_encryption(username, pwd):
    m = hashlib.md5()
    m.update(username.encode())
    m.update(pwd.encode())
    return m.hexdigest()


while 1:
    op = input("請選擇操作(1-註冊   2-登入   0-退出) :")
    if op == '0':
        break
    elif op == '1':
        username = input('請輸入使用者名稱:')
        password = input('請輸入密  碼:')
        if regist(username, password):
            print('註冊成功')
        else:
            print('使用者名稱密碼不能為空!')
    elif op == '2':
        username = input('請輸入使用者名稱:')
        password = input('請輸入密  碼:')
        if login(username, password):
            print('登入成功')
        else:
            print('登入失敗')
    else:
        print('輸入錯誤,請重新輸入!!!')

collections模組

這個模組提供了抽象基類,可以用來建立一個特定的介面

Counter類

Counter類是dict的一個子類,它的引數是一個可雜湊的物件或者一個對映,並返回一個字典,字典的鍵是可雜湊物件的每個元素,值是該鍵的數量。還有一個most_common() 方法可以獲取返回值的前n個

例1:

import collections

ret = collections.Counter('this is a test')
print(ret)
print(ret.most_common(3))					# 獲取前三個值
ret2 = collections.Counter(cats=3, dogs=4)
print(ret2)

執行結果:

Counter({'t': 3, 's': 3, ' ': 3, 'i': 2, 'h': 1, 'a': 1, 'e': 1}) # 鍵是字串中的字元,值是字元的個數統計

[('t', 3), ('s', 3), (' ', 3)]

Counter({'dogs': 4, 'cats': 3})

namedtuple類

namedtuple類是元組的子類,命名元組對於為csv或sqlite3模組返回的結果元組分配欄位名稱特別有用

語法:

conllections.namedtuple('說明', [變數1, 變數2])

說明:

  1. 說明 必須沒有空格,可以帶下劃線
  2. 變數必須是字串

例1:

import collections

Point = collections.namedtuple('說明', ['x', 'y'])
p = Point(12, 23)
ret = p.x + p.y
print(ret)

執行結果:

35

defaultdict類

defaultdict是字典dict的一個子類,用法跟字典類似,引數是一個default_factory

語法:

collections.defaultdict([default_factory[, ...]])

例1:

s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
d = collections.defaultdict(list)
for k, v in s:
    d[k].append(v)

ret = d.items()
print(ret)
print(dict(ret))

執行結果:

dict_items([('yellow', [1, 3]), ('blue', [2, 4]), ('red', [1])])
{'yellow': [1, 3], 'blue': [2, 4], 'red': [1]}