1. 程式人生 > >Python基礎(四)常用模組

Python基礎(四)常用模組

模組(Module):在python中,一個.py檔案就稱之為一個模組。模組共分為三種:python標準庫、第三方模組和應用程式自定義模組

模組匯入:

1. import 語句:import module1[, module2[,... moduleN]
2. from…import 語句:from modname import name1[, name2[, ... nameN]]
3. from…import* 語句

模組匯入的本質是通過sys.path找到檔案,然後執行該指令碼(全部執行),然後將將變數名載入到名字空間

常用模組:datetime、time、random、os、sys、json、pickle、re、logging、configparse、hashlib

datatime模組

print(datetime.datetime.now())
#2018-09-03 17:07:03.651692

time模組

三種表達形式:

1.時間戳 time()
print(time.time())
#1535961077.9106913

2.結構化時間 localtime()、gmtime()
#----當地時間---- 
print(time.localtime())
#time.struct_time(tm_year=2018, tm_mon=9, tm_mday=3, tm_hour=15, tm_min=51, tm_sec=17, tm_wday=0, tm_yday=246, tm_isdst=0)
#----UTC---- print(time.gmtime()) #time.struct_time(tm_year=2018, tm_mon=9, tm_mday=3, tm_hour=7, tm_min=51, tm_sec=17, tm_wday=0, tm_yday=246, tm_isdst=0) 3.字串時間 asctime()、ctime() # asctime() 把一個表示時間的元組或者struct_time表示為這種形式:'Sun Jun 20 23:21:05 1993'。如果沒有引數,將會將time.localtime()作為引數傳入。 print(time.asctime()) #Mon Sep 3 16:56:18 2018
#ctime()把一個時間戳(按秒計算的浮點數)轉化為time.asctime()的形式。如果引數未給或者為None的時候,將會預設time.time()為引數。它的作用相當於time.asctime(time.localtime(secs)) print(time.ctime()) #Mon Sep 3 16:59:20 2018

三種表現形式的相互轉換:
這裡寫圖片描述

將結構化時間轉化為時間戳 mktime()
print(time.mktime(time.localtime()))
#1535964519.0

將結構化時間轉化為字串時間 strftime()
print(time.strftime('%Y-%m-%d %X',time.localtime()))
#2018-09-03 16:48:39

將字串時間轉換為結構化時間 strptime()
print(time.strptime('2018-09-03 16:48:39','%Y-%m-%d %X'))
#time.struct_time(tm_year=2018, tm_mon=9, tm_mday=3, tm_hour=16, tm_min=48, tm_sec=39, tm_wday=0, tm_yday=246, tm_isdst=-1)     

random模組

import random
print(random.random())          #0-1之間的隨機數
print(random.randint(1,5))      #大於等於1小於等於5的整數
print(random.randrange(1,3))    #大於等於1小於3
print(random.choice([11,22,33]))    #對一個可迭代物件的隨機選取
print(random.sample([11,22,33],2))  #隨機選取兩個
print(random.uniform(1,3))      #1.2461267518206374

驗證碼:

checkcode = ''
for i in range(6):
    num = random.randint(0,9)
    alf = chr(random.randint(65,90))
    res = random.choice([num,alf])
    checkcode += str(res)
print(checkcode)
#3SC2Z7

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下為"\r\n",Linux下為"\n"
os.pathsep              #輸出用於分割檔案路徑的字串 win下為;,Linux下為:
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所指向的檔案或者目錄的最後修改時間    

sys模組

sys.argv        #命令列引數List,第一個元素是程式本身路徑
sys.exit(n)     #退出程式,正常退出時exit(0)
sys.version     #獲取Python解釋程式的版本資訊
sys.maxint      #最大的Int值
sys.path        #返回模組的搜尋路徑,初始化時使用PYTHONPATH環境變數的值
sys.platform    #返回作業系統平臺名稱

進度條

import sys,time
for i in range(10):
    sys.stdout.write('#')
    time.sleep(0.1)
    sys.stdout.flush()

json & pickle

序列化和反序列化:我們把物件(變數)從記憶體中變成可儲存或傳輸的過程稱之為序列化,在Python中叫pickling,序列化之後,就可以把序列化後的內容寫入磁碟,或者通過網路傳輸到別的機器上。反過來,把變數內容從序列化的物件重新讀到記憶體裡稱之為反序列化,即unpickling

json:
如果我們要在不同的程式語言之間傳遞物件,就必須把物件序列化為標準格式,比如XML,但更好的方法是序列化為JSON,因為JSON表示出來就是一個字串,可以被所有語言讀取,也可以方便地儲存到磁碟或者通過網路傳輸。JSON不僅是標準格式,並且比XML更快,而且可以直接在Web頁面中讀取,非常方便。

之前我們學習過用eval內建方法可以將一個字串轉成python物件,不過,eval方法是有侷限性的,對於普通的資料型別,json.loads和eval都能用,但遇到特殊型別的時候,eval就不管用了,所以eval的重點還是通常用來執行一個字串表示式,並返回表示式的值。

import json
#序列化
dic={'name':'alvin','age':23,'sex':'male'}

j = json.dumps(dic)
print(type(j))  # <class 'str'>

f = open('json_test','w')
f.write(j)  # 等價於 json.dump(dic,f)
f.close()

#反序列化
f = open('json_test')
data = json.loads(f.read()) # 等價於data=json.load(f)
print(data)

#注意點
import json
# x = "{'name':'user'}"
# print(json.loads(x))      #報錯,json不認單引號
x = '{"name":"user"}'
print(json.loads(x))

pickle:

import pickle
#序列化
dic={'name':'alvin','age':23,'sex':'male'}

j = pickle.dumps(dic)
print(type(j))  # <class 'bytes'>

f = open('pickle_test','wb')    # 注意是w是寫入str,wb是寫入bytes,j是'bytes'
f.write(j)  # 等價於pickle.dump(dic,f)
f.close()

#反序列化
f = open('pickle_test','rb')
data = pickle.loads(f.read())   # 等價於data=pickle.load(f)
print(data)

re模組

常用方法:

re.findall()    # 返回所有滿足匹配條件的結果,放在列表裡
re.finditer()   # 同findall,將查詢結果封裝到迭代器中,返回的是一個可迭代物件,處理大資料量時非常有用
re.search()     # 函式會在字串內查詢模式匹配,只到找到第一個匹配然後返回一個包含匹配資訊的物件,該物件可以通過呼叫group()方法得到匹配的字串,如果字串沒有匹配,則返回None。
re.match()      # 同search,不過盡在字串開始處進行匹配
re.split()      # 分割
re.sub()        # 替換
re.subn()       
re.compile()    

用法示例:

>>> import re
>>> re.findall('\d+','abc123def456')    #返回所有滿足匹配條件的結果,放在列表裡
['123', '456']

>>> re.finditer('\d+','abc123def456')
<callable_iterator object at 0x000000000286DAC8>
>>> ret = re.finditer('\d+','abc123def456')
>>> next(ret).group()     
'123'
>>> next(ret).group()
'456'

>>> re.search('\d+','abc123def456')     #函式會在字串內查詢模式匹配,只到找到第一個匹配然後返回一個包含匹配資訊的物件
<_sre.SRE_Match object; span=(3, 6), match='123'>
>>> re.search('\d+','abc123def456').group()    #該物件可以通過呼叫group()方法得到匹配的字串,如果字串沒有匹配,則返回None。
'123'

>>> re.match('\d+','abc123def456').group()  #同search,不過盡在字串開始處進行匹配
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'
>>> re.match('\d+','111abc123def456').group()
'111'

>>> re.split('[ab]','abcd')     #先按'a'分割得到''和'bcd',在對''和'bcd'分別按'b'分割
['', '', 'cd']

>>> re.sub('\d+','AAA','123abc123def456')
'AAAabcAAAdefAAA'
>>> re.sub('\d+','AAA','123abc123def456',2)
'AAAabcAAAdef456'
>>> re.subn('\d+','AAA','123abc123def456')
('AAAabcAAAdefAAA', 3)

>>> obj = re.compile('\d{3}')   #定義的規則可以使用多次
>>> obj.search('abc123def456')
<_sre.SRE_Match object; span=(3, 6), match='123'>
>>> obj.search('abc123def456').group()
'123'
>>> obj.search('abc456').group()
'456'
>>> re.findall('abc?','abcccc')
['abc']
>>> re.findall('abc*','abcccc')
['abcccc']
>>> re.findall('abc+','abcccc')
['abcccc']
>>> re.findall('abc+?','abcccc')
['abc']
>>> re.findall('abc*?','abcccc')
['ab']

2.在python直譯器中\\等價於正則中的\

>>> re.findall('a\\\\k','a\k')
['a\\k']
>>> re.findall(r'a\\k','a\k')
['a\\k']

3.分組的特殊用法 (?P<group>pattern)

>>> re.search('(?P<name>[a-z]+)(?P<age>\d{2})','user22')
<_sre.SRE_Match object; span=(0, 6), match='user22'>
>>> ret = re.search('(?P<name>[a-z]+)(?P<age>\d{2})','user18')
>>> ret.group()
'user18'
>>> ret.group('name')
'user'
>>> ret.group('age')
'18'

4.?: 去優先順序

>>> re.findall('www\.(baidu|163)\.com','abcwww.baidu.com123')
['baidu']   #findall會優先把匹配結果組裡內容返回,如果想要匹配結果,取消許可權即可
>>> re.findall('www\.(?:baidu|163)\.com','abcwww.baidu.com123')
['www.baidu.com']

logging模組

1.簡單應用

import logging
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message') 

輸出:
WARNING:root:warning message
ERROR:root:error message
CRITICAL:root:critical message
#預設情況下Python的logging模組將日誌列印到了標準輸出中,且只顯示了大於等於WARNING級別的日誌,這說明預設的日誌級別設定為WARNING(日誌級別等級CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET),預設的日誌格式為日誌級別:Logger名稱:使用者輸出訊息。

2.靈活配置日誌級別,日誌格式,輸出位置

import logging
logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S',
                    filename='test.log',
                    filemode='w')

logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')

輸出:
Fri, 14 Sep 2018 08:57:56 module_test.py[line:167] DEBUG debug message
Fri, 14 Sep 2018 08:57:56 module_test.py[line:168] INFO info message
Fri, 14 Sep 2018 08:57:56 module_test.py[line:169] WARNING warning message
Fri, 14 Sep 2018 08:57:56 module_test.py[line:170] ERROR error message
Fri, 14 Sep 2018 08:57:56 module_test.py[line:171] CRITICAL critical message

logging.basicConfig()函式中可通過具體引數來更改logging模組預設行為,可用引數有:

filename:用指定的檔名建立FiledHandler(後邊會具體講解handler的概念),這樣日誌會被儲存在指定的檔案中。
filemode:檔案開啟方式,在指定了filename時使用這個引數,預設值為“a”還可指定為“w”。
format:  指定handler使用的日誌顯示格式。 
datefmt: 指定日期時間格式。 
level:   設定rootlogger(後邊會講解具體概念)的日誌級別 
stream:  用指定的stream建立StreamHandler。可以指定輸出到sys.stderr,sys.stdout或者檔案(f=open('test.log','w')),預設為sys.stderr。若同時列出了filename和stream兩個引數,則stream引數會被忽略。

format引數中可能用到的格式化串:

%(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    使用者輸出的訊息

3.logger物件
上述幾個例子中我們瞭解到了logging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical()(分別用以記錄不同級別的日誌資訊),logging.basicConfig()(用預設日誌格式(Formatter)為日誌系統建立一個預設的流處理器(StreamHandler),設定基礎配置(如日誌級別等)並加到root logger(根Logger)中)這幾個logging模組級別的函式,另外還有一個模組級別的函式是logging.getLogger([name])(返回一個logger物件,如果沒有指定名字將返回root logger)

import logging

logger = logging.getLogger()
#logger = logging.getLogger('mylogger')
#logger.setLevel(logging.INFO)

# 建立一個handler,用於寫入日誌檔案
fh = logging.FileHandler('test.log')

# 再建立一個handler,用於輸出到控制檯
ch = logging.StreamHandler()

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

fh.setFormatter(formatter)
ch.setFormatter(formatter)

logger.addHandler(fh) #logger物件可以新增多個fh和ch物件
logger.addHandler(ch)

logger.debug('logger debug message')
logger.info('logger info message')
logger.warning('logger warning message')
logger.error('logger error message')
logger.critical('logger critical message')

輸出:
2018-09-14 09:03:57,566 - root - WARNING - logger warning message
2018-09-14 09:03:57,567 - root - ERROR - logger error message
2018-09-14 09:03:57,567 - root - CRITICAL - logger critical message
#Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical()輸出不同級別的日誌,只有日誌等級大於或等於設定的日誌級別的日誌才會被輸出。這裡沒有用logger.setLevel(logging.Debug)顯示的為logger設定日誌級別,所以使用預設的日誌級別WARNIING,故結果只輸出了大於等於WARNIING級別的資訊。

logging庫提供了多個元件:Logger、Handler、Filter、Formatter。Logger物件提供應用程式可直接使用的介面,Handler傳送日誌到適當的目的地,Filter提供了過濾日誌資訊的方法,Formatter指定日誌顯示格式。

configparse模組

使用python生成類似mysql、haproxy配置檔案這樣的文件,以my.cny為例:

import configparser
config = configparser.ConfigParser()

config['client'] = {'port':3306,
                    'socket':'/var/lib/mysql/mysql.sock'}
config['mysqld'] = {'port':3306,
                    'socket':'/var/lib/mysql/mysql.sock',
                    'server_id':1,
                    'datadir':'/data/mydata',
                    'character_set_server':'utf8',
                    'innodb_file_per_table':'1',
                    'binlog_format':'mixed'}
config['mysqldump'] = {}
config['mysqldump']['max_allowed_packet'] = '16M'

config['myisamchk'] = {}
topsecret = config['myisamchk']
topsecret['key_buffer_size'] = '8M'
topsecret['sort_buffer_size'] = '8M'

with open('my.cnf','w') as configfile:
    config.write(configfile)

生成結果:

[client]
port = 3306
socket = /var/lib/mysql/mysql.sock

[mysqld]
port = 3306
socket = /var/lib/mysql/mysql.sock
server_id = 1
datadir = /data/mydata
character_set_server = utf8
innodb_file_per_table = 1
binlog_format = mixed

[mysqldump]
max_allowed_packet = 16M

[myisamchk]
key_buffer_size = 8M
sort_buffer_size = 8M

增刪查改:

import configparser
config = configparser.ConfigParser()

#-------查--------------
print(config.sections())    # []

config.read('my.cnf')
print(config.sections())    # ['client', 'mysqld', 'mysqldump', 'myisamchk']

print('mysqld' in config)   # True
print('mysql' in config)    # False

print(config['client']['port'])     # 3306
print(config['mysqld']['binlog_format'])    # mixed

for key in config['myisamchk']:
    print(key)
    #key_buffer_size
    #sort_buffer_size

print(config.options('myisamchk'))  # ['key_buffer_size', 'sort_buffer_size']
print(config.items('myisamchk'))    # [('key_buffer_size', '8M'), ('sort_buffer_size', '8M')]
print(config.get('myisamchk','key_buffer_size'))    # 8M    

#---------------增、刪、改(config.write(open('filename','w')))------------
config.read('my.cnf')

config.add_section('mysql')     # 新增一個[mysql]標籤段
config.remove_section('mysqldump')  #刪除[mysqldump]標籤段
config.remove_option('client','port')
config.set('client','default-character-set','utf8')

config.write(open('my.cnf1','w'))   

hashlib模組

用於加密相關的操作,3.x裡代替了md5模組和sha模組,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512, MD5 演算法。

import hashlib
hash = hashlib.md5()    # hash = hashlib.sha256()
hash.update('hello'.encode('utf8'))
print(hash.hexdigest())     # 5d41402abc4b2a76b9719d911017c592

hash.update('world'.encode('utf8'))
print(hash.hexdigest())     # fc5e038d38a57032085441e7fe7010b0

hash1 = hashlib.md5()
hash1.update('helloworld'.encode('utf8'))
print(hash1.hexdigest())    # fc5e038d38a57032085441e7fe7010b0

以上加密演算法雖然依然非常厲害,但有時候存在缺陷,即:通過撞庫可以反解。所以,有必要對加密演算法中新增自定義key再來做加密。

import hashlib
hash = hashlib.md5('salt'.encode('utf8'))
hash.update('hello'.encode('utf8'))
print(hash.hexdigest())     # 06decc8b095724f80103712c235586be

python 還有一個 hmac 模組,它內部對我們建立 key 和 內容 再進行處理然後再加密:

import hmac
h = hmac.new('salt'.encode('utf8'))
h.update('hello'.encode('utf8'))
print(h.hexdigest())       # 3a2484b4f0df4f4157d069598a334b31