1. 程式人生 > 實用技巧 >7.常用模組

7.常用模組

目錄

一、模組

import 模組名

'''
1、建立名為da17的名稱空間

2、執行此名稱空間的所有程式碼

3、通過da17.xx的方式引用
'''

模組的匯入

# sys.path.append(r'D:\code\acb ')  # 使用的是絕對路徑
# 使用相對路徑找到位置

# print(__file__)  # 當前的絕對路徑

# 使用os獲取一個路徑的父路徑
# print(os.path.dirname(__file__)+r'\acb')

# sys.path.append(os.path.dirname(__file__)+ r'\acb')  # 使用相對路徑匯入模組

相對匯入

  • 一個點意味著引用的模組或包位於與當前位置相同的目錄中
  • 兩個點意味著它在當前位置的父目錄中,也就是上層的目錄。
  • 三個點意味著它在祖父母目錄中,

匯入包會執行某個下的__init__模組,一個py檔案中有相對匯入是不可以直接執行的。

from ... import * 和 import ...的區別

  • from ... import *:匯入模組時,會跳過私有屬性
  • import ...:通過引用可以訪問私有屬性

二、random模組

# random 隨機數
import random
# random.random()  # 獲取0.0-1.0之間的浮點數
# random.randint(a, b) # 獲取[a, b)範圍內的整數
# random.uniform(a, b) # 獲取[a,b)之間的浮點數
# random.shuffle(x) # 把引數指定的資料中的元素打亂,引數必須是一個可變的資料型別
# random.sample(x, k)  # 從x中隨機抽取k個數據,組成一個列表返回

collections模組

collections 模組中的三個常用類

namedtuple():命名元組

defaultdict():預設值字典

Counter():計數器

namedtuple():命名元組

from collections import namedtuple
Rectangle = namedtuple('Rectangle_class', ['length', 'width'])
r = Rectangle(10, 5)
print(r)		# Rectangle_class(length=10, width=5)
# 通過訪問元組的元素
print(r.length)
print(r.width)
print(type(r))    # 輸出<class '__main__.Rectangle_class'>
# 通過索引的方式訪問元素
print(r[1])

# Counter:計數器
c = Counter('asdasdadwqeasd')
print(c)
print(c.most_common(3)) # 取前三

defaultict():設定預設值字典

from collections import defaultdict
d = defaultdict(int, name='An', age=12)
print(d['name'])
print(d['age'])
print(d['addr'])    # {'addr':'0'}  也會別新增
print(d)

# 自定義函式充當第一個引數
# def func():
#     return 'hello'   # 最佳鍵的預設值

# d = defaultdict(func, ame='an', age=11)
# print(d['addr'])		# hello
# print(d['tell'])		# hello
# print(d)						# defaultdict(<function func at 0x0000017F0EA54EE0>, {'ame': 'an', 'age': 11, 'addr': 'hello', 'tell': 'hello'})

Counter():計數器

from collections import  Counter
c = Counter('asdasdadwqeasd')
print(c)
print(c.most_common(3)) # 取前三

三、hashlib模組

加密類
MD5 不可逆加密結果用於驗證,並非解密,
兩個資料的MD5相同,表示原文相同

MD5是最常見的摘要演算法,生成結果是128bit位元組,通常是一個32位的16進位制字串表示。另一種摘要演算法是SHA1,和呼叫MD5類似。SHA1的結果是160bit位元組,通常用40位的16進位制字串表示。還有SHA256和SHA512,他們更安全但是更慢。

'''
1、把一個大的資料,切分成不同的小塊,分別對不同的塊加密和直接對大塊加密結果一樣
2、單向不可逆
3、原始資料的小變化導致結果的大差異
'''

'''
1、獲取加密物件
2、使用update方法,可以呼叫多次
3、呼叫hexdigest()方法輸出加密後的md5
'''

import hashlib
# 獲取加密物件
m = hashlib.md5()
# 使用加密物件的update進行加密
m.update(b'asfnaj')  # 傳入位元組型別引數
# m.update('中文'.encode('utf-8'))
res = m.hexdigest()
# print(res)

# 不同的加密演算法實質就是加密結果的長度不同
# 建立加密物件時,可以指定引數,稱為salt,把update的引數傳入hashlib.md5()中
# m = hashlib.md5(b'asfnaj')
# m.update()
# print(m.hexdigest())

# 多次對小塊加密,與小塊合成的大塊加密結果相同

# 登入註冊驗證
op = int(input('1、註冊2、登入3、退出'))
def get_md5(username, password):
    m = hashlib.md5()
    m.update(username.encode('utf-8'))
    m.update(password.encode('utf-8'))
    return m.hexdigest()

def register(username, password):
    res = get_md5(username, password)
    with open('login', mode='at')as f:
        f.write(res + '\n')

def login(username, password):
    res = get_md5(username,password)
    with open('login', mode='rt',encoding='utf-8')as f:
        for line in f:
            if res == line.strip():
                return True
            else:
                return False 
if op == 1:
    username = input('輸入使用者名稱')
    password = input('輸入密碼')
    register(username, password)
elif op == 2:
    username = input('輸入使用者名稱')
    password = input('輸入密碼')
    login(username, password)
    if res:
        print('登入成功')
    else:
        print('登入失敗')

四、json模組

序列化和反序列化

物件(或變數)從記憶體變成可儲存或可傳輸的過程稱之為序列化

json

json模組是將滿足條件的資料結構轉化成特殊的字串,並且也可以反序列化還原回去。

序列化(serialization):結構化資料--->線性資料, 反序列化(deserialization)

線性資料:資料之間沒有應用關係

結構化資料:記憶體中

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

# 元組序列化後變成列表
# print(json.dumps((1, 3, 5)))

json可以序列化的型別:元組,字典,int

json模組的四個方法:

  • 用於網路傳輸:dumps、loads
  • 用於檔案寫讀:dump、load

dumps、loads

import json
dic1 = {'k1':'v1','k2':'v2','k3':'v3'}
str_dic = json.dumps(dic)  #序列化:將一個字典轉換成一個字串
print(type(str_dic),str_dic)  #<class 'str'> {"k3": "v3", "k1": "v1", "k2": "v2"}
#注意,json轉換完的字串型別的字典中的字串是由""表示的

dic2 = json.loads(str_dic)  #反序列化:將一個字串格式的字典轉換成一個字典
#注意,要用json的loads功能處理的字串型別的字典中的字串必須由""表示
print(type(dic2),dic2)  #<class 'dict'> {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}

list_dic = [1,['a','b','c'],2,{'k1':'v1','k2':'v2'}]
str_dic = json.dumps(list_dic) 
print(type(str_dic),str_dic) #<class 'str'> [1, ["a", "b", "c"], 2, {"k1": "v1", "k2": "v2"}]
list_dic2 = json.loads(str_dic)
print(type(list_dic2),list_dic2) #<class 'list'> [1, ['a', 'b', 'c'], 3, {'k1': 'v1', 'k2': 'v2'}]

dump、load

import json
dic = {'k1':'v1','k2':'v2','k3':'v3'}
with open('json_file','w')as f1:
    json.dump(dic,f1)  #dump方法接收一個檔案控制代碼,直接將字典轉換成json字串寫入檔案

with open('json_file')as f2:
    dic2 = json.load(f2)  #load方法接收一個檔案控制代碼,直接將檔案中的json字串轉換成資料結構返回
    print(type(dic2),dic2)

五、pickle模組

pickle也是同於序列化和反序列化的模組,區別在於

  • json,用於字串和 python資料型別間進行轉換
  • pickle,用於python特有的型別 和 python的資料型別間進行轉換

pickle模組提供了四個功能:dumps、dump(序列化,存)、loads(反序列化,讀)、load (不僅可以序列化字典,列表...python中任意的資料型別都可序列化

pickle比json強大,但是json是其他語言都支援的,pickle只有python支援。

import pickle
dic = {'k1':'v1','k2':'v2','k3':'v3'}
str_dic = pickle.dumps(dic)
print(str_dic)  # pickle轉化成一串二進位制內容,json是字串

dic2 = pickle.loads(str_dic)
print(dic2)    #字典

和檔案相關的dump和load

import time
# 獲取時間物件
struct_time  = time.localtime(100000000)
print(struct_time)
# pickle序列化
with open('pickle_file','wb')as f1:
    pickle.dump(struct_time,f1)
# pickle反序列化
with open('pickle_file','rb')as f2:
    struct_time2 = pickle.load(f2)
    print(struct_time2.tm_year)

六、os模組

os.path中常用的檔案處理函式。

函式名 說明
abspath(path) 返回path所在的絕對路徑
dirname(path) 返回目錄的路徑
exists(path) 判斷檔案是否存在
getatime(filename) 返回指定檔案的的最近訪問時間
getctime(path) 返回指定檔案的建立時間
getmtime(path) 返回指定檔案的最新的修改時間
getsize(filename) 返回指定檔案的大小,單位是位元組
isdir(path) 判斷是否為文目錄
isfile(path) 判斷是否為檔案
split(path) 分割檔名與路徑並返回一個列表
splitext(path) 從路徑中分割檔案的拓展名
walk(top,func,arg) 遍歷目錄數

getatime()、getctime()、getmtime()返回的都是時間戳。可通過time.gmtime([sec])轉換的得到一個物件,再通過該物件的tm_year,tm_mon,tm_mday等屬性獲取相應時間或日期

os模組下常用的檔案操作函式

os.remove(filename) # 刪除檔案

os.listdir() # 列出當前目錄的所有檔案,返回一個列表,如['an.txt','bn.txt','cn.txt']

os.rename('要修改的檔案、目錄名', '修改後的檔案、目錄名') # 檔案或目錄的重新命名

七、sys模組

# 直譯器相關操作
import sys
# sys.argv  傳遞給python指令碼的命令引數列表
# print(sys.argv[0]) # 指令碼名
# print('第一個引數', sys.argv[1])
# print('第二個引數', sys.argv[2])
# print(sys.platform) # 返回執行python指令碼的系統的平臺,當前是win32

# 直譯器尋找模組的路徑
# sys.path

八、time模組

time 和時間相關,主要用於顯示

時間戳:從時間元年(1970 1 1 00:00:00)到現在經過的秒數

struct_time型別,九個欄位組成,分別是tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst,

函式 說明
time.time() 返回一個float型別的時間戳
time.gmtime([seconds]) 獲取格式化時間物件(struct_time型別)
time.localtime([seconds]) 獲取格式化的時間物件(struct_time型別)
time.mktime(t) 時間物件->時間戳
time.strftime(format[ ,t]) 把時間按物件格式轉化成字串
time.strptime(str, format) 把時間字串轉化為一個struct_time型別的
time.gmtime() 獲取現在的時間戳,struct_time型別
time.asctime() 返回當前時間的字串形式
import time
print(time.time())		# 獲取現在的時間戳
# print(time.gmtime(1))     # 元年經過1秒對應的時間物件

# 格式化的時間物件和字串之間的轉換
# s = time.strftime('year:%Y %m %d %H:%M:%S')
# print(s)

# 把時間字串轉換為時間物件
# time_obj = time.strptime('2020 10 1', '%Y %m %d')
# print(time_obj,type(time_obj))

九、datetime模組

datetime : 與日期時間相關,主要用於計算

三個主要類,只有他們能計算

date 需要年,月,日三個引數

datetime 需要年,月,日,時,分,秒六個引數

timedelta 需要一個時間段,可以是天,秒,微妙

# 時間變化量
# td = datetime.timedelta(days=1)
# print(td)

# 時間變化量會產生進位
# t = datetime.datetime(2020,10,10,10,1,59)
# d = datetime.timedelta(seconds=6)
# t = t + d
# print(t)

十、logging模組

python的logging模組提供了標準的日誌介面,你可以通過它儲存各種格式的日誌。

logging的日誌分為debug()、info()、warning()、error()、critical()五個級別

  • debug() 除錯模式(詳細)
  • info() 記錄(無錯誤)
  • warning() 無錯誤但可能有潛在的危險
  • error() 出現錯誤
  • critical() 嚴重問題

1 基本用法

日誌列印

import logging
logging.warning('')
logging.critical('server is down')
# WARNING:root:user
# CRITICAL:root:server is down

日誌寫入檔案

import logging

logging.basicConfig(filename='log_test.log', level=logging.INFO)
logging.debug('debug')
logging.info('info')
logging.warning('warning')

# log_test.log只寫入warning和info資訊

在basicConfig中,filename指定了檔案路徑,level=logging.INFO是把日誌記錄設定為INFO,只輸入INFO或者比INFO級別更高的日誌(日誌級別過濾)。

自定義日誌格式

import logging

logging.basicConfig(filename='log_test.log', level=logging.DEBUG,format='%(asctime)s-%(name)s-%(filename)s-%(funcName)s-%(lineno)d-%(message)s'),  # 引數格式固定

datefmt = '%m/%d/%/Y% %T:%M:%S'

logging.error('from sayhi...')
logging.debug('debug')
logging.info('info')
logging.warning('warning')

除了在日誌格式上加時間外,還可以自定義很多格式

引數格式介紹:
%(levelno)s     # 列印數字形式的日誌級別(10對應debug,20對應info,30對應warning)
%(levelname)s   # 列印文字形式的日誌級別 %(pathname)s    # 呼叫日誌輸出函式的模組的完整路徑名
%(filename)s    # 呼叫日誌輸出函式的模組的檔名

%(module)s      # 呼叫日誌輸出函式的模組名
%(funcName)s    # 呼叫日誌輸出函式的函式名
%(lineNo)d      # 呼叫日誌輸出函式的語句所在的程式碼行(44)
%(created)f     # 當前時間,用UNIX標準的表示是時間(一般時間用datafmt即可)
%(relaticeCreated)d    # 輸出日誌資訊時,自Logger建立以來的毫秒數

%(asctime)s     # 字串形式的當前時間,預設格式"2003-08-08 16:32:21,878",逗號後為毫秒數

%(thread)d      # 執行緒ID  
%(threadName)s  # 執行緒名
%(process)d     # 程序ID

%(message)s     # 使用者輸出的訊息

日誌同時輸出到螢幕和檔案

Python使用logging模組記錄日誌涉及四個主要類:
  1、logger提供了應用程式可以直接使用的介面;
  2、handler將(logger建立的)日誌記錄傳送到合適的目的輸出;
  3、filter對記錄的日誌過濾決定哪條日誌輸出;
  4、formatter決定日誌記錄的最終輸出格式。

# 同時向檔案和螢幕上輸出 和 亂碼
fh = logging.FileHandler('tmp.log',encoding='utf-8')
# fh2 = logging.FileHandler('tmp2.log',encoding='utf-8')
sh = logging.StreamHandler()
logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s[line :%(lineno)d]-%(module)s:  %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S %p',
    level= logging.DEBUG,
    # handlers=[fh,sh,fh2]
    handlers=[fh,sh]
)
logging.debug('debug 資訊錯誤 test2')
logging.info('warning 資訊錯誤 test2')
logging.warning('warning message test2')
logging.error('error message test2')
logging.critical('critical message test2')

日誌的切分

# 做日誌的切分
import time
from logging import handlers
sh = logging.StreamHandler()
rh = handlers.RotatingFileHandler('myapp.log', maxBytes=1024,backupCount=5)   # 按照大小做切割
fh = handlers.TimedRotatingFileHandler(filename='x2.log', when='s', interval=5, encoding='utf-8')
logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s[line :%(lineno)d]-%(module)s:  %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S %p',
    level= logging.DEBUG,
    # handlers=[fh,sh,fh2]
    handlers=[fh,rh,sh]
)
for i in range(1,100000):
    time.sleep(1)
    logging.error('KeyboardInterrupt error %s'%str(i))

十一、functools模組

partial函式

functools存放了很多的工具函式,常用的兩個:

  • partial函式(偏函式):綁定了一部分引數的函式。作用就是少傳引數,將部分引數和函式繫結,不需要傳入相同的引數。
  • wraps函式:避免多個函式被兩個裝飾器裝飾時就報錯,因為兩個函式名一樣,第二個函式再去裝飾的話就報錯,最好是加上這個,程式碼更加健壯
# 案例一
def add(a,b):
  return a+b

add = partial(add, 3)
add(6)		# 9

# 案例二
def show(*args,**kwargs):
  print(args)
  print(kwargs)

show = partial(show, 1,2,3,4)
show()		# (1,2,3,4) {}
show(name='an', age=11)		# (1,2,3,4) {'name':'an', age:11}

wraps函式

wraps函式:新增裝飾器後函式名和函式的doc發生了改變,用此方法消除副作用。

def note(func):
    def wrapper(*args):
        print('note smomething')
        return func(*args)
    return wrapper

@note
def test():
    '''函式文件'''
    print('i am test')

test()
print(test.__doc__)
print(test.__name__)
# 列印結果
# note smomething
# i am test
# None
# wrapper

上述程式碼中發現test的__doc__屬性丟失,__name__屬性也變成了wrapper,使用wraps可以避免這個問題,

from functools import partial,wraps
def note(func):
    @wraps(func)   # 這裡加了wraps裝飾器
    def wrapper(*args):
        print('note smomething')
        return func(*args)
    return wrapper

@note
def test():
    '''函式文件'''
    print('i am test')

test()
print(test.__doc__)
print(test.__name__)
# 列印結果
# note smomething
# i am test
# 函式文件
# test

從上面可以看到test函式的doc和name屬性都沒有被改變。