在計算機程序的開發過程當中,隨着程序代碼越寫越多,在一個文件裏代碼就會愈來愈長,愈來愈不容易維護。爲了編寫可維護的代碼,咱們把不少函數分組,分別放到不一樣的文件裏,分組的規則就是把實現了某個功能的代碼集合,放置到一個模塊中,這樣,每一個文件包含的代碼就相對較少,不少編程語言都採用這種組織代碼的方式。在Python中,一個.py文件就稱之爲一個模塊(Module)。模塊也被叫作庫。html
一、模塊內有許多函數方法,利用這些方法能夠更簡單的完成許多工做。
二、模塊能夠在文件中永久保存代碼。在python交互式解釋器中操做輸入的代碼,在退出python時是不會被保存的,而模塊文件中的代碼是永久存在的。
三、從實用性方面來講,模塊能夠跨系統平臺使用,只須要Copy代碼就能夠。好比說,有一個全局對像,會被許多文件使用,這時爲了方便把它寫入一個模塊中,再被調用是最好的方法。node
內置模塊 :Python官方提供的一些模塊功能,好比:random,json,string,base64,pickle,sys,os等python
自定義模塊:根據本身需求編寫的一些.py文件或一類模塊以及包。linux
第三方模塊:非Python自己自帶的一些模塊甚至框架。好比:request,Image,Flask,Django,Scrapy等。正則表達式
模塊的導入使用import語句來完成。 import module1[, module2[,... moduleN] 若是導入的模塊和主程序在同個目錄下,直接import就好了。算法
若是導入的模塊是在主程序所在目錄的子目錄下,能夠在子目錄中增長一個空白的__init__.py文件,該文件使得python解釋器將子目錄整個也當成一個模塊,而後直接經過「import 子目錄.模塊」導入便可。shell
若是導入的模塊是在主程序所在目錄的父目錄下,則要經過修改path來解決,有兩種方法:數據庫
(1)經過」import sys,sys.path.append('父目錄的路徑')「來改變,這種方法屬於一次性的,只對當前的python解釋器進程有效,關掉python重啓後就失效了。編程
(2)直接修改環境變量:在windows中是 「 set 變量=‘路徑’ 」 例如:set PYTHONPATH=‘C:\test\...’ 查看是否設置成功用echo %PYTHONPATH%,並且進到python解釋器中查看sys.path,會發現已經有了新增長的路徑了。這種方式是永久的,一次設置之後一直都有效。json
注意:經過修改path是通用的方法,由於python解釋器就是經過sys.path去一個地方一個地方的尋找模塊,且當前目錄優先導入。
擴展補充:
還有一種動態導入模塊的方法,以字符串方式導入,能夠根據用戶輸入,或者url等來進行動態建立導入模塊的語句,案例以下:
1 inp = input("請輸入要訪問的url:") 2 m, f = inp.split("/") 3 obj = __import__(m) 4 # 這樣導入的m模塊,就被實例到對象obj。 5 6 7 # 帶入帶路徑的模塊,擴展:__import__的使用 8 # __import__("lib.xxx.xxx.xx"+ m) 默認狀況下只導入lib 9 # __import__("lib.xxx.xxx.xx"+ m, fromlist=True) fromlist參數可使它導入lib.xx.xx.xx,使多層次導入生效。默認爲單層
案例代碼:
1 def run(): 2 inp = input("請輸入要訪問的url:") 3 if hasattr(commons, inp): 4 func = getattr(commons, inp) # commons是模塊,inp是對應函數 5 func() 6 else:print("不存在")
因爲Python在導入模塊的時候,是按照sys.path路徑去順序查找,所以,若是在當前目錄下找到的話,就會終止向下查找,所以模塊的命名應該避免與第三方模塊、內置模塊衝突。
模塊的編寫與常規函數的編寫無其餘區別,須要注意的就是儘可能聚合一類功能的代碼放入一個模塊中,提升了整合度,也方便其餘人來調用。同時還能夠提升構建項目時,包的有序性和可維護性。
__doc__ 函數、或者文檔的註釋
__file__ 獲取當前運行的py文件所在的目錄
__cached__ __pycache__的路徑,知道就行
__name__ 1. 獲取函數的名稱 2.只有執行當前文件時,當前文件的特殊變量__name__ 就等於「__main__」
__package__ 輸出對應函數屬於哪一個包 . admin.__package__
包括了一組很是實用的服務,內含不少函數方法和變量,用來處理Python運行時配置以及資源,從而能夠與當前程序以外的系統環境交互
1)sys.argv 獲取一個命令行參數的list。 第一個元素是python腳本名稱,其他的每一個元素相似shell中傳參的$1, $2, $3....$n
2)sys.path 查找模塊所在目錄的目錄名列表。經常使用來添加其餘目錄的包或者模塊
import sys, os # 程序主目錄 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # 添加主目錄至環境變量,一般寫於文件首部位置 sys.path.append(BASE_DIR) print(sys.path[0], type(sys.path[0])) #out: E:\學習經歷\python勃起\SVN目錄\S13-Day05\class <class 'str'>
3)sys.exit(n) 退出程序,正常退出時exit(0).
4)sys.platform 返回操做系統平臺名稱
5)sys.stdin 輸入相關
6)sys.stdout 輸出相關,實際上,這就是print函數真正作的事情:它在你打印的字符串後面加上一個硬回車,而後調用 sys.stdout.write 函數。
7)sys.stderr 錯誤相關
這個模塊包含廣泛的操做系統功能。若是你但願你的程序可以與平臺無關的話,這個模塊是尤其重要的。即它容許一個程序在編寫後不須要任何改動,也不會發生任何問題,就能夠在Linux和Windows下運行。
1 os.getcwd() 獲取當前工做目錄,即當前python腳本工做的目錄路徑 2 3 os.chdir("dirname") 改變當前腳本工做目錄;至關於shell下cd 4 os.makedirs('dir1/dir2') 可生成多層遞歸目錄,至關於linux中的mkdir -p 5 os.removedirs('dirname1') 若目錄爲空,則刪除,並遞歸到上一級目錄,如若也爲空,則刪除,依此類推 6 os.mkdir('dirname') 生成單級目錄;至關於shell中mkdir dirname 7 os.rmdir('dirname') 刪除單級空目錄,若目錄不爲空則沒法刪除,報錯;至關於shell中rmdir dirname 8 os.listdir('dirname') 列出指定目錄下的全部文件和子目錄,包括隱藏文件,並以列表方式打印 9 os.remove() 刪除一個文件 10 os.rename("oldname","new") 重命名文件/目錄 11 os.stat('path/filename') 獲取文件/目錄信息 12 os.sep 操做系統特定的路徑分隔符,win下爲"\\",Linux下爲"/" 13 os.linesep 當前平臺使用的行終止符,win下爲"\t\n",Linux下爲"\n" 14 os.pathsep 用於分割文件路徑的字符串,windows下爲";",Linux下爲":" 15 os.name 字符串指示當前使用平臺。win->'nt'; Linux->'posix' 16 os.system("bash command") 運行shell命令,並輸出對應結果 17 os.environ 獲取系統環境變量 18 os.path.abspath(path) 返回path規範化的絕對路徑 19 os.path.split(path) 將path分割成目錄和文件名二元組返回 20 os.path.dirname(path) 返回path的目錄。其實就是os.path.split(path)的第一個元素 21 os.path.basename(path) 返回path最後的文件名。如何path以/或\結尾,那麼就會返回空值。即os.path.split(path)的第二個元素 22 os.path.exists(path) 若是path存在,返回True;若是path不存在,返回False 23 os.path.isabs(path) 若是path是絕對路徑,返回True 24 os.path.isfile(path) 若是path是一個存在的文件,返回True。不然返回False 25 os.path.isdir(path) 若是path是一個存在的目錄,則返回True。不然返回False 26 os.path.join(path1[, path2[, ...]]) 將多個路徑組合後返回,第一個絕對路徑以前的參數將被忽略 27 os.path.getatime(path) 返回path所指向的文件或者目錄的最後存取時間 28 os.path.getmtime(path) 返回path所指向的文件或者目錄的最後修改時間
重點:os.path.join,用於鏈接多個字符串來組成路徑,能夠根據不一樣的操做系統,生成不一樣表現形式的地址 ,'/','\'
python中的隨機數模塊,經常使用的幾個方法以下:
1 random.random() 用於生成一個0到1的隨機浮點數: 0 <= n < 1.0 2 random.uniform(a,b) 用於生成一個指定範圍內的隨機符點數,兩個參數其中一個是上限,一個是下限 3 random.randint(a, b) 用於生成一個指定範圍內的整數。其中參數a是下限,參數b是上限,生成的隨機數n: a <= n <= b 4 random.randrange([start], stop[, step]) 從指定範圍內,按指定基數遞增的集合中 獲取一個隨機數 5 random.choice 從序列中獲取一個隨機元素。其函數原型爲:random.choice(sequence)。參數sequence表示一個有序類型 6 random.sample(sequence, k) 從指定序列中隨機獲取指定長度的片段
1 import time 2 import datetime 3 4 print(time.time()) #返回當前系統時間戳 5 print(time.ctime()) #輸出Tue Jan 26 18:23:48 2016 ,當前系統時間 6 print(time.ctime(time.time()-86640)) #將時間戳轉爲字符串格式 7 print(time.gmtime(time.time()-86640)) #將時間戳轉換成struct_time格式 8 print(time.localtime(time.time()-86640)) #將時間戳轉換成struct_time格式,但返回 的本地時間 9 print(time.mktime(time.localtime())) #與time.localtime()功能相反,將struct_time格式轉回成時間戳格式 10 #time.sleep(4) #sleep 11 print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()) ) #將struct_time格式轉成指定的字符串格式 12 print(time.strptime("2016-01-28","%Y-%m-%d") ) #將字符串格式轉換成struct_time格式 13 14 #datetime module 15 16 print(datetime.date.today()) #輸出格式 2016-01-26 17 print(datetime.date.fromtimestamp(time.time()-864400) ) #2016-01-16 將時間戳轉成日期格式 18 current_time = datetime.datetime.now() # 19 print(current_time) #輸出2016-01-26 19:04:30.335935 20 print(current_time.timetuple()) #返回struct_time格式 21 22 #datetime.replace([year[, month[, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]]]]]) 23 print(current_time.replace(2014,9,12)) #輸出2014-09-12 19:06:24.074900,返回當前時間,但指定的值將被替換 24 25 str_to_date = datetime.datetime.strptime("21/11/06 16:30", "%d/%m/%y %H:%M") #將字符串轉換成日期格式 26 new_date = datetime.datetime.now() + datetime.timedelta(days=10) #比如今加10天 27 new_date = datetime.datetime.now() + datetime.timedelta(days=-10) #比如今減10天 28 new_date = datetime.datetime.now() + datetime.timedelta(hours=-10) #比如今減10小時 29 new_date = datetime.datetime.now() + datetime.timedelta(seconds=120) #比如今+120s 30 print(new_date)
json,用於字符串 和 python數據類型間進行轉換.更加適合跨語言(通常都是字符串)
json.loads 將字符串轉換爲python的數據類型
json.dumps 將python的基本數據類型轉換爲字符串
1 import json 2 dic = '{"k1":1, "k2":2}' 3 print(json.loads(dic), type(json.loads(dic))) 4 5 out: {'k1': 1, 'k2': 2} <class 'dict'> 6 7 8 9 dic = {'k1':1} 10 s = json.dumps(dic) 11 print(s, type(s)) 12 13 out: {"k1": 1} <class 'str'>
json.load 從文件讀取json數據格式的字符串,進而轉換成python中的數據格式
json.dump 將json數據,寫入文件
1 import json, os 2 li = [11, 22, 33] 3 json.dump(li, open('write.txt', 'w')) 4 os.system("type write.txt") 5 6 out: [11, 22, 33] 7 8 9 LI = json.load(open('write.txt', 'r')) 10 print(LI, type(LI)) 11 12 out: [11, 22, 33] <class 'list'>
pickle,用於python特有的類型和 python的數據類型間進行轉換,對python複雜類型作操做,是一種持久化存儲的方式。缺點:python版本之間的不一樣,可能會致使沒法反序列化其餘版本的序列化結果或文件。
pickle.loads 將bytes數據類型轉換爲對應的python數據類型
pickles.dumps 將python數據類型轉換爲bytes對象
1 import pickle 2 li = [11,22,33] 3 r = pickle.dumps(li) 4 print(r, type(r)) 5 6 out: b'\x80\x03]q\x00(K\x0bK\x16K!e.' <class 'bytes'> 7 8 9 s = pickle.loads(r) 10 print(s, type(s)) 11 12 out: [11, 22, 33] <class 'list'>
pickle.load 從pickle數據格式的文件中讀取數據,並轉化爲python數據格式。
pickles.dump 將python數據格式,存儲入文件中,返回None
1 import pickle 2 li = [11,22,33] 3 r = pickle.dump(li,open("write.txt",'wb')) 4 print(r, type(r)) 5 6 out: None <class 'NoneType'> 7 8 s = pickle.load(open("write.txt",'rb'), encoding='utf-8') 9 print(s, type(s)) 10 11 out: [11, 22, 33] <class 'list'>
日誌模塊基本上是全部程序中最經常使用的功能, 而logging模塊屬於python內置的一個模塊(注意,是內置哦,能夠跨平臺使用,能夠跨平臺使用,能夠跨平臺使用,重要的事情說三遍)。若是簡單的打印日誌信息到文件,使用很是簡單,分爲如下倆步:
1)定義文件 2)輸出信息 (若是隻是輸出至屏幕,第一步「1」)能夠省去)
1 import logging, os 2 3 logging.basicConfig(filename='example.log',level=logging.INFO) 4 logging.debug('This message should go to the log file') 5 logging.info('So should this') 6 logging.warning('And this, too') 7 os.system("type example.log") 8 9 out: 10 INFO:root:So should this 11 WARNING:root:And this, too
上邊示例代碼中,其實日誌等級level不是必須配置的,默認level=warning。輸出不一樣級別的日誌,只有日誌等級大於或等於設置的日誌級別的日誌纔會被輸出。所有的日誌級別以下:
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. |
logging.basicConfig的其餘配置參數:
filename Specifies that a FileHandler be created, using the specified filename, rather than a StreamHandler.#定義輸出文件名 filemode Specifies the mode to open the file, if filename is specified (if filemode is unspecified, it defaults to 'a').#定義輸出日誌文件的打開方式,默認爲append追加模式。 format Use the specified format string for the handler.#定義日誌格式 datefmt Use the specified date/time format.#定義時間格式,即%(asctime)的格式 style If a format string is specified, use this to specify the type of format string (possible values '%', '{', '$', for %-formatting, :meth:`str.format` and :class:`string.Template` - defaults to '%'). level Set the root logger level to the specified level.#定義日誌輸出級別 stream Use the specified stream to initialize the StreamHandler. Note that this argument is incompatible with 'filename' - if both are present, 'stream' is ignored.#與finename配置項衝突,共存時此項配置忽略 handlers If specified, this should be an iterable of already created handlers, which will be added to the root handler. Any handler in the list which does not have a formatter assigned will be assigned the formatter created in this function.
其中format是最經常使用的一個參數,用來定義日誌格式,好比:format
=
'%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s'
%()s中,分別表明什麼呢?看下錶:(着重關注:levelname,filename, module, lineno, funcName, asctime, message)
%(name)s Name of the logger (logging channel) %(levelno)s Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL) %(levelname)s Text logging level for the message ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL") %(pathname)s Full pathname of the source file where the logging call was issued (if available) %(filename)s Filename portion of pathname %(module)s Module (name portion of filename) %(lineno)d Source line number where the logging call was issued (if available) %(funcName)s Function name %(created)f Time when the LogRecord was created (time.time() return value) %(asctime)s Textual time when the LogRecord was created %(msecs)d Millisecond portion of the creation time %(relativeCreated)d Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded (typically at application startup time) %(thread)d Thread ID (if available) %(threadName)s Thread name (if available) %(process)d Process ID (if available) %(message)s The result of record.getMessage(), computed just as the record is emitted
案例1:將日誌打印到屏幕
import logging logging.debug('This is debug message') logging.info('This is info message') logging.warning('This is warning message') logging.critical('This is critical message') logging.error('This is error message') out: WARNING:root:This is warning message CRITICAL:root:This is critical message ERROR:root:This is error message
#上邊示例中,發現只有warning級別以上的打印到屏幕,是由於默認記錄level爲warning的緣由,上邊已經說到過。
案例2:將日誌同時輸出到屏幕和日誌
import logging #define logfile/logformat/loglevel for file log 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='example.log', filemode='w') #create logger obj logger = logging.getLogger('CURRENT-USER') logger.setLevel(logging.DEBUG) #create console handler and set level to INFO ch = logging.StreamHandler() ch.setLevel(logging.INFO) # define log format for console log formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') ch.setFormatter(formatter) # add console handle to logger obj logger.addHandler(ch) logger.debug('This is debug message') logger.info('This is info message') logger.warning('This is warning message') logger.critical('This is critical message') logger.error('This is error message')
最終終端展現:
2016-06-08 16:26:50,007 - CURRENT-USER - INFO - This is info message 2016-06-08 16:26:50,007 - CURRENT-USER - WARNING - This is warning message 2016-06-08 16:26:50,007 - CURRENT-USER - CRITICAL - This is critical message 2016-06-08 16:26:50,010 - CURRENT-USER - ERROR - This is error message
最終文件內容:
Wed, 08 Jun 2016 16:30:35 practice3.py[line:183] DEBUG This is debug message Wed, 08 Jun 2016 16:30:35 practice3.py[line:184] INFO This is info message Wed, 08 Jun 2016 16:30:35 practice3.py[line:185] WARNING This is warning message Wed, 08 Jun 2016 16:30:35 practice3.py[line:186] CRITICAL This is critical message Wed, 08 Jun 2016 16:30:35 practice3.py[line:187] ERROR This is error message
案例3:設置log rotate(TimedRotatingFileHandler和RotatingFileHandler)
不管是TimedRotatingFileHandler仍是RotatingFileHandler,都是繼承自logging.FileHandler。
#定義一個RotatingFileHandler,最多備份5個日誌文件,每一個日誌文件最大238byte Rthandler = RotatingFileHandler('example.log', maxBytes=238,backupCount=5) Rthandler.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s') Rthandler.setFormatter(formatter) logging.getLogger('').addHandler(Rthandler) logging.debug('This is debug message') logging.info('This is info message') logging.warning('This is warning message') logging.critical('This is critical message') logging.error('This is error message')
更多的用法,參照http://www.cnblogs.com/dkblog/archive/2011/08/26/2155018.html
PS. 還有一個日誌的第三方模塊,syslog感受沒有logging好用,關鍵不支持跨平臺操做(windows就不能夠)。因此這裏不做過多說明。
因爲只是簡單使用hashlib.md5() , hashlib.sha1() , hashlib.sha256() , hashlib.sha384() , hashlib.sha512() 的話,能夠經過撞庫的方式進行反解,所以有必要對加密算法中添加自定義key再來作加密,即加鹽。以sha512加鹽加密爲例,其他的使用方法同樣。
1 import hashlib 2 3 hash = hashlib.sha512('nihao'.encode('utf-8')) 4 hash.update('123'.encode("utf-8")) 5 print(hash.hexdigest()) 6 7 out: 480ad41a6a159cba1811ccac4561845816e9a488cc992b0979a73065560e6a30f34a1f1a051c7044ae7d636df0327cc4f3bb7f54e129e4d76688f389394c257c
Ps: 須要額外注意,python在全部平臺上均可以使用的加密算法以下:
>>> hashlib.algorithms_guaranteed
{'sha224', 'sha512', 'sha256', 'sha384', 'sha1', 'md5'}
hmac主要應用在身份驗證中,它的使用方法是這樣的:
1. 客戶端發出登陸請求(假設是瀏覽器的GET請求)
2. 服務器返回一個隨機值,並在會話中記錄這個隨機值
3. 客戶端將該隨機值做爲密鑰,用戶密碼進行hmac運算,而後提交給服務器
4. 服務器讀取用戶數據庫中的用戶密碼和步驟2中發送的隨機值作與客戶端同樣的hmac運算,而後與用戶發送的結果比較,若是結果一致則驗證用戶合法
在這個過程當中,可能遭到安全攻擊的是服務器發送的隨機值和用戶發送的hmac結果,而對於截獲了這兩個值的黑客而言這兩個值是沒有意義的,絕無獲取用戶密碼的可能性,隨機值的引入使hmac只在當前會話中有效,大大加強了安全性和實用性
1 import hmac 2 myhmac = hmac.new(b'suijizhi') 3 myhmac.update(b'mypassword') 4 print(myhmac.hexdigest()) 5 6 out: 7b6a9485f5b1f513d6d55b24642db70c
擴展閱讀:哈希長度擴展攻擊解析
科普哈希長度擴展攻擊(Hash Length Extension Attacks)_百度安全論壇
1)re.match(pattern, string, flags=0) 從起始位置開始根據模型去字符串中匹配指定內容,匹配單個.起始位置不匹配,則返回None
# 標誌位以下
I = IGNORECASE = sre_compile.SRE_FLAG_IGNORECASE # ignore case
L = LOCALE = sre_compile.SRE_FLAG_LOCALE # assume current 8-bit locale
U = UNICODE = sre_compile.SRE_FLAG_UNICODE # assume unicode locale
M = MULTILINE = sre_compile.SRE_FLAG_MULTILINE # make anchors look for newline
S = DOTALL = sre_compile.SRE_FLAG_DOTALL # make dot match newline
X = VERBOSE = sre_compile.SRE_FLAG_VERBOSE # ignore whitespace and comments
案例:
import re # 匹配第一個單詞 text = "JGood is a handsome boy, he is cool, clever, and so on..." m = re.match(r"(\w+)\s", text) print(m) print(m.group()) print(m.group(0)) print(m.group(1)) out: <_sre.SRE_Match object; span=(0, 6), match='JGood '> JGood_ # _表示空格 JGood_ JGood
從上面結果能夠看出, m.group() = m.group(0) = m.group(1) + '\s'
2) re.search(pattern, string, flags=0) 在字符串內查找模式匹配,匹配單個,只到找到第一個匹配而後返回,若是字符串沒有匹配,則返回None。
text = "JGood is a handsome boy, he is cool, clever, and so on..." m = re.search(r"\w{8}\s", text) print(m) print(m.group()) print(m.group(0)) out: <_sre.SRE_Match object; span=(11, 20), match='handsome '> handsome_ # _表示空格 handsome_
3)從上邊的print(m) 能夠看到,匹配結果返回一個 SRE_Match object,下面講講這個Object 的幾個經常使用方法:
group([group1,…])
返回匹配到的一個或者多個子組。若是是一個參數,那麼結果就是一個字符串,若是是多個參數,那麼結果就是一個參數一個item的元組。group1的默認等於0(即返回全部的匹配值).若是groupN參數爲0,相對應的返回值就是所有匹配的字符串,若是group1的值是[1…99]範圍以內的,那麼 將匹配對應括號組的字符串。若是組號是負的或者比pattern中定義的組號大,那麼將拋出IndexError異常。若是pattern沒有匹配到,可是group匹配到了,那麼group的值也爲None。若是一個pattern能夠匹配多個,那麼組對應的是樣式匹配的最後一個。另外,子組是根據括號從左向右來進行區分的。
groups([default])
返回一個包含全部子組的元組。Default是用來設置沒有匹配到組的默認值的。Default默認是"None」。
groupdict([default])
返回匹配到的全部命名子組的字典。Key是name值,value是匹配到的值。參數default是沒有匹配到的子組的默認值。這裏與groups()方法的參數是同樣的。默認值爲None
4)findall(pattern, string, flags=0) 獲取字符串中全部匹配的字符串
1 text = "JGood is a handsome boy, he is cool, clever, and so on..." 2 obj = re.findall('\wo{2}\w', text) 3 print(obj) 4 5 out: ['Good', 'cool']
5) re.sub(pattern, repl, string, count=0, flags=0) re.sub用於替換字符串中的匹配項。
1 text = "JGood is a handsome boy, he is cool, clever, and so on..." 2 obj = re.sub(r'\s+', '-', text) # 將空格替換成「-」 3 print(obj) 4 5 out: 6 JGood-is-a-handsome-boy,-he-is-cool,-clever,-and-so-on...
6)re.split(pattern, string, maxsplit=0, flags=0) 根據指定匹配進行分組
1 text = "JGood is a handsome boy, he is cool, clever, and so on..." 2 obj = re.split(r'\s+', text) #以空格爲分隔符進行切分 3 print(obj) 4 5 out: 6 ['JGood', 'is', 'a', 'handsome', 'boy,', 'he', 'is', 'cool,', 'clever,', 'and', 'so', 'on...']
7) re.compile(pattern, flags=0) 能夠把正則表達式編譯成一個正則表達式對象。能夠把那些常用的正則表達式編譯成正則表達式對象,這樣能夠提升必定的效率
1 import re 2 3 text = "JGood is a handsome boy, he is cool, clever, and so on..." 4 regex = re.compile(r'\w*oo\w*') 5 print(regex.findall(text)) #查找全部包含'oo'的單詞 6 print(regex.sub(lambda m: '[' + m.group(0) + ']', text)) #將字符串中含有'oo'的單詞用[]括起來。 7 8 out: 9 ['JGood', 'cool'] 10 [JGood] is a handsome boy, he is [cool], clever, and so on...
1)聲明1:文件格式以下:
[section1] # 節點1 k1 = v1 # 值1 k2:v2 # 值2 [section2] # 節點2 k1 = v1 # 值1
聲明2:configparser取出的值,默認都爲str類型,所以存儲的時候也要傳入str類型的參數。若是但願取出的值爲其餘類型,能夠經過以下方式進行轉換
config.getint(setion_name, key_name) , config.getfloat(setion_name, key_name), config.getboolean(setion_name, key_name)
2)獲取全部的節點section : config.sections() 返回值是一個list
3)獲取指定節點下鍵值對 : config.items(section_name)
4)獲取指定節點下全部的key : config.options(section_name)
5)獲取指定節點下指定的key : config.get(section_name, key_name)
6)檢查、刪除、增長節點 :
config.has_section(section_name)
config.remove_section(section_name)
config.add_section(section_name)
7)檢查、刪除、設置指定section中的鍵值 :
config.has_option(section_name, key_name)
config.remove_option(section_name, key_name)
config.set(section_name, key_name, value)
用途:1. 頁面上作展現 2.配置文件
存儲方式:1.文件
2.內部數據XML格式
1)解析XML
解析XML有兩種方式,第一種是直接解析,就是直接將xml文件,加載到內存,解析爲xml對象。
第二種是間接解析,就是將xml經過open函數讀入內存,而後將讀出的str類型數據,解析爲xml對象。
測試數據以下:
# filename : example.xml
<data> <country name="Liechtenstein"> <rank updated="yes">2</rank> <year>2023</year> <gdppc>141100</gdppc> <neighbor direction="E" name="Austria" /> <neighbor direction="W" name="Switzerland" /> </country> <country name="Singapore"> <rank updated="yes">5</rank> <year>2026</year> <gdppc>59900</gdppc> <neighbor direction="N" name="Malaysia" /> </country> <country name="Panama"> <rank updated="yes">69</rank> <year>2026</year> <gdppc>13600</gdppc> <neighbor direction="W" name="Costa Rica" /> <neighbor direction="E" name="Colombia" /> </country> </data>
結構分析圖:
直接解析
from xml.etree import ElementTree as ET # 直接解析XML # ElementTree 類型具備將內存中xml數據寫入文件的屬性,而Element不具有 tree = ET.parse("example.xml") root = tree.getroot() print(root) out: <Element 'data' at 0x0000000000A56138>
間接解析
from xml.etree import ElementTree as ET str_xml = open('example.xml', 'r').read() root = ET.XML(str_xml) print(root) out: <Element 'data' at 0x0000000000C37818>
2)遍歷XML文檔中的全部內容
from xml.etree import ElementTree as ET tree = ET.parse("example.xml") root = tree.getroot() for child in root: print(child, child.tag, child.attrib) for gradechild in child: print(gradechild, gradechild.tag, gradechild.text, gradechild.attrib, ) out: <Element 'country' at 0x0000000000E03AE8> country {'name': 'Liechtenstein'} <Element 'rank' at 0x0000000000E18318> rank 2 {'updated': 'yes'} <Element 'year' at 0x0000000000E18368> year 2023 {} <Element 'gdppc' at 0x0000000000E183B8> gdppc 141100 {} <Element 'neighbor' at 0x0000000000E18408> neighbor None {'direction': 'E', 'name': 'Austria'} <Element 'neighbor' at 0x0000000000E18458> neighbor None {'direction': 'W', 'name': 'Switzerland'} <Element 'country' at 0x0000000000E184A8> country {'name': 'Singapore'} <Element 'rank' at 0x0000000000E184F8> rank 5 {'updated': 'yes'} <Element 'year' at 0x0000000000E18548> year 2026 {} <Element 'gdppc' at 0x0000000000E18598> gdppc 59900 {} <Element 'neighbor' at 0x0000000000E185E8> neighbor None {'direction': 'N', 'name': 'Malaysia'} <Element 'country' at 0x0000000000E18638> country {'name': 'Panama'} <Element 'rank' at 0x0000000000E18688> rank 69 {'updated': 'yes'} <Element 'year' at 0x0000000000E186D8> year 2026 {} <Element 'gdppc' at 0x0000000000E18728> gdppc 13600 {} <Element 'neighbor' at 0x0000000000E18778> neighbor None {'direction': 'W', 'name': 'Costa Rica'} <Element 'neighbor' at 0x0000000000E187C8> neighbor None {'direction': 'E', 'name': 'Colombia'}
遍歷XML某個節點的全部內容
from xml.etree import ElementTree as ET str_xml = open('example.xml', 'r').read() root = ET.XML(str_xml) for node in root.iter('year'): # 去全部子和子孫節點中,找尋year節點 print(node.tag, node.text) out: year 2023 year 2026 year 2026
3)修改節點內容
from xml.etree import ElementTree as ET # 打開文件,讀取XML內容 str_xml = open('example.xml', 'r').read() # 將字符串解析成xml特殊對象,root代指xml文件的根節點 root = ET.XML(str_xml) ############ 操做 ############ # 頂層標籤 print(root.tag) # 循環全部的year節點 for node in root.iter('year'): # 將year節點中的內容自增一 new_year = int(node.text) + 1 node.text = str(new_year) # 設置屬性 node.set('name', 'alex') node.set('age', '18') # 刪除屬性 del node.attrib['name'] ############ 保存文件 ############ tree = ET.ElementTree(root) tree.write("test3.xml", encoding='utf-8')
刪除節點
# 直接解析xml文件 tree = ET.parse("example.xml") # 獲取xml文件的根節點 root = tree.getroot() ############ 操做 ############ # 頂層標籤 print(root.tag) # 遍歷data下的全部country節點 for country in root.findall('country'): # 獲取每個country節點下rank節點的內容 rank = int(country.find('rank').text) if rank > 50: # 刪除指定country節點 root.remove(country) ############ 保存文件 ############ tree.write("test-delnode.xml", encoding='utf-8')
在原xml基礎上建立節點
from xml.etree import ElementTree as ET tree = ET.parse("example.xml") root = tree.getroot() # ele = ET.Element() ele = ET.Element('test', {'k1': 'v1'}) ele.text = "內容" # 在無text內容的時候,採用自閉合標籤,即<test k1='v1' /> # def __init__(self, tag, attrib={}, **extra): root.append(ele) tree.write('createxml.xml', encoding='utf-8')
4)建立XML文檔
4.1) 方式1:嫁接的方式生成XML文檔。即先生成子孫,而後將子孫嫁接到root部位,最後保存,完成整個建立工做
from xml.etree import ElementTree as ET # 建立根節點 root = ET.Element("family") # 建立節點大兒子 son1 = ET.Element('son', {'name': 'lisi'}) # 建立節點小兒子 son2 = ET.Element('son', {'name': 'zhangsan'}) # 在大兒子中建立兩個孫子 grandson1 = ET.Element('grandson', {'name': 'wangwu'}) grandson2 = ET.Element('grandson', {'name': 'maliu'}) # 把孫子添加到父親節點中 son1.append(grandson1) son2.append(grandson2) # 把父親添加到爺爺節點中 root.append(son1) root.append(son2) # 將爺爺節點轉換爲Etree類型 tree = ET.ElementTree(root) # 默認狀況下write,會保存爲一行,沒有縮進 # tree.write("create_new_xml.xml", encoding='utf-8') tree.write("create_new_xml.xml", encoding='GBK', xml_declaration=True, short_empty_elements=False) # short_empty_elements = True表示開啓自封閉標籤,False表示關閉自封閉標籤 # xml_declaration = None時,若是爲US-ASCII 或者UTF-8則不添加聲明,其餘編碼格式添加聲明。若是爲True則永遠添加聲明.False關閉添加聲明
建立結果以下:
<?xml version='1.0' encoding='GBK'?> <family><son name="lisi"><grandson name="wangwu"></grandson></son><son name="zhangsan"><grandson name="maliu"></grandson></son></family>
能夠看到,利用原生的XML保存文件時,默認沒有縮進。所以須要修改保存方式
def prettify(elem): """將節點轉換成字符串,並添加縮進。 """ rough_string = ET.tostring(elem, 'utf-8') reparsed = minidom.parseString(rough_string) return reparsed.toprettyxml(indent="\t") from xml.dom import minidom from xml.etree import ElementTree as ET # 建立根節點 root = ET.Element("family") # 建立節點大兒子 son1 = ET.Element('son', {'name': 'lisi'}) # 建立節點小兒子 son2 = ET.Element('son', {'name': 'zhangsan'}) # 在大兒子中建立兩個孫子 grandson1 = ET.Element('grandson', {'name': 'wangwu'}) grandson2 = ET.Element('grandson', {'name': 'maliu'}) # 把孫子添加到父親節點中 son1.append(grandson1) son2.append(grandson2) # 把父親添加到爺爺節點中 root.append(son1) root.append(son2) raw_str = prettify(root) f = open("create_new_xml.xml",'w',encoding='utf-8') f.write(raw_str) f.close()
4.2)方式2:開枝散葉的方式生成XML文檔。即子孫由root開始,長出son,再基於son長出grandson,依次生長,最後保存,完成整個建立工做。
from xml.etree import ElementTree as ET # 建立根節點 root = ET.Element("famliy") # 建立大兒子 # son1 = ET.Element('son', {'name': '兒1'}) son1 = root.makeelement('son', {'name': '兒1'}) # 建立小兒子 # son2 = ET.Element('son', {"name": '兒2'}) son2 = root.makeelement('son', {"name": '兒2'}) # 在大兒子中建立兩個孫子 # grandson1 = ET.Element('grandson', {'name': '兒11'}) grandson1 = son1.makeelement('grandson', {'name': '兒11'}) # grandson2 = ET.Element('grandson', {'name': '兒12'}) grandson2 = son1.makeelement('grandson', {'name': '兒12'}) son1.append(grandson1) son1.append(grandson2) # 把兒子添加到根節點中 root.append(son1) root.append(son1) tree = ET.ElementTree(root) tree.write('oooo.xml',encoding='utf-8', short_empty_elements=False)
4.3)方式3:以拼湊的方式生成XML文檔。即以某個節點爲準,直接插入對應節點的子節點位置。
from xml.etree import ElementTree as ET # 建立根節點 root = ET.Element("famliy") # 建立節點大兒子 son1 = ET.SubElement(root, "son", attrib={'name': '兒1'}) # 建立小兒子 son2 = ET.SubElement(root, "son", attrib={"name": "兒2"}) # 在大兒子中建立一個孫子 grandson1 = ET.SubElement(son1, "age", attrib={'name': '兒11'}) grandson1.text = '孫子' et = ET.ElementTree(root) #生成文檔對象 et.write("test.xml", encoding="utf-8", xml_declaration=True, short_empty_elements=False)
5)命名空間:暫時沒用到,用到了再說!
參考連接: http://www.w3school.com.cn/xml/xml_namespaces.asp
1)將文件內容拷貝到另外一個文件中
1 import shutil 2 shutil.copyfileobj(open('old.txt','r'), open('new.txt', 'w'))
2)拷貝文件
shutil.copyfile('old.txt', 'new.txt')
3)僅拷貝權限。內容、組、用戶均不變
shutil.copymode('old.txt', 'new.txt')
4)僅拷貝狀態的信息,包括:mode bits, atime, mtime, flags
shutil.copystat('old.txt', 'new.txt')
5)拷貝文件和權限
shutil.copy('old.txt', 'new.txt')
6)拷貝文件和狀態信息
shutil.copy2('old.txt', 'new.txt')
7)遞歸的去拷貝文件夾
shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))
8)遞歸的去刪除文件夾
shutil.rmtree('folder1')
shutil模塊對於壓縮包的處理很弱,所以選用其餘模塊來處理壓縮包。這裏介紹zipfile和tarfile兩個模塊。
import zipfile # 壓縮。 壓縮以後源文件不消失 z = zipfile.ZipFile('test.zip', 'w') # w表示建立新的,a表示追加 z.write('file_1.log') # file必須存在,不然會報錯FileNotFoundError z.write('file_2.txt') z.close() # 解壓 z = zipfile.ZipFile('test.zip', 'r') # 查看壓縮包中文件名列表 print(z.namelist()) # 解壓單個文件 z.extract('file_1.log') # 解壓所有文件 z.extractall() z.close()
# 壓縮 tar = tarfile.open('test.tar','w') tar.add('file_1.log', arcname='bbs2.log') # 壓縮後可改變壓縮名 tar.add('file_2.txt') # 不寫arcname的話,文件名保持不變 tar.close() # 解壓 tar = tarfile.open('test.tar','r') # 獲取壓縮文件的文件名列表 print(tar.getnames()) # 解壓單個文件 tar.extract("file_2.txt") # 解壓所有文件 tar.extractall() # 可設置解壓地址,默認爲當前目錄 tar.close()
在執行一些Linux系統命令的時候,有多種方式:好比os.system(command) , os.popen(commond).read(), commands.getstatusoutput(command) 等方法。以上執行shell命令的相關的模塊和函數的功能均在 subprocess 模塊中實現,並提供了更豐富的功能。
subprocess包中定義有數個建立子進程的函數,這些函數分別以不一樣的方式建立子進程,因此咱們能夠根據須要來從中選取一個使用。另外subprocess還提供了一些管理標準流(standard stream)和管道(pipe)的工具,從而在進程間使用文本通訊。
1)subprocess.call() 執行命令,返回狀態碼,至關於return exit_code
retcode = subprocess.call(["ls", "-l"], shell=False)
retcode = subprocess.call("ls -l", shell=True)
爲何用shell=True:
shell=False時,該方法的執行是以os.execvp(file, args)來執行的,若是接收一個列表或元組,則列表第一個元素當作命令,以後的當作參數進行執行。若是接收一個字符串,則認爲該字符串是一個可執行文件的文件名,會執行該文件,文件不存在報:OSError: [Errno 2] No such file or directory
咱們使用了shell=True這個參數。Python將先運行一個shell,再用這個shell來解釋這整個字符串。shell命令中有一些是shell的內建命令,這些命令必須經過shell運行,$cd。shell=True容許咱們運行這樣一些命令。
2)subprocess.check_call() 執行命令,若是執行狀態碼是0,能夠取到返回的狀態碼,不然報出錯誤subprocess.CalledProcessError(returncode, cmd, output=None, stderr=None),該對象包含有returncode屬性
subprocess.check_call(["ls", "-l"], shell=False)
subprocess.check_call("ls -l", shell=True)
import subprocess
b = subprocess.CalledProcessError
try:
subprocess.check_call('fff', shell=True)
except b:
print b
out:/bin/sh: fff: command not found
Command 'fff' returned non-zero exit status 127
3)subprocess.check_output() 執行命令,若是執行狀態碼是 0 ,則返回執行結果,且return值存在,若是return code不爲0,則舉出錯誤subprocess.CalledProcessError,該對象包含有returncode屬性和output屬性,output屬性爲標準輸出的輸出結果。
retinfo = subprocess.check_output(["ls", "-l"], shell=False)
retinfo = subprocess.check_output("ls -l", shell=True)
上述的三個方法,本質上都是調用了subprocess.Popen()方法。
4)subprocess.Popen(self, args, bufsize=-1, executable=None,stdin=None, stdout=None, stderr=None,preexec_fn=None, lose_fds=_PLATFORM_DEFAULT_CLOSE_FDS,shell=False, cwd=None, env=None, universal_newlines=False,startupinfo=None, creationflags=0,restore_signals=True, start_new_session=False,pass_fds=()) 用戶執行復雜的命令
參數:
args:shell命令,能夠是字符串或者序列類型(如:list,元組)
bufsize:指定緩衝。0 無緩衝,1 行緩衝,其餘 緩衝區大小,負值 系統緩衝
stdin, stdout, stderr:分別表示程序的標準輸入、輸出、錯誤句柄
preexec_fn:只在Unix平臺下有效,用於指定一個可執行對象(callable object),它將在子進程運行以前被調用
close_sfs:在windows平臺下,若是close_fds被設置爲True,則新建立的子進程將不會繼承父進程的輸入、輸出、錯誤管道。
因此不能將close_fds設置爲True同時重定向子進程的標準輸入、輸出與錯誤(stdin, stdout, stderr)。
shell:同上
cwd:用於設置子進程的當前目錄
env:用於指定子進程的環境變量。若是env = None,子進程的環境變量將從父進程中繼承。
universal_newlines:不一樣系統的換行符不一樣,True -> 贊成使用 \n
startupinfo與createionflags只在windows下有效。將被傳遞給底層的CreateProcess()函數,用於設置子進程的一些屬性,如:主窗口的外觀,進程的優先級等等
import subprocess ret1 = subprocess.Popen(["mkdir","t1"]) ret2 = subprocess.Popen("mkdir t2", shell=True)
終端輸入的命令分爲兩種:
情景1:輸入後即刻獲得輸出
import subprocess obj = subprocess.Popen("mkdir t3", shell=True, cwd='/home/dev',)
情景2:輸入進行某環境,依賴再輸入
import subprocess obj = subprocess.Popen(["python3"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) obj.stdin.write("print(1)\n") obj.stdin.write("print(2)") obj.stdin.close() cmd_out = obj.stdout.read() obj.stdout.close() cmd_error = obj.stderr.read() obj.stderr.close() print(cmd_out) print(cmd_error)
import subprocess obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) obj.stdin.write("print(1)\n") obj.stdin.write("print(2)") out_error_list = obj.communicate() print(out_error_list) # out_error_list = (stdout, stderr)
import subprocess obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) out_error_list = obj.communicate('print("hello")') print(out_error_list) # if self.universal_newlines is True, this should be a string; if it is False, "input" should be bytes.
# universal_newlines=True表示以text的方式打開stdout和stderr。