Python基礎學習筆記(20)遞迴詳解 shutil 模組 logging 模組
Python基礎學習(20)遞迴詳解 shutil 模組 logging 模組
一、今日大綱
- 遞迴詳解
- shutil 模組
- logging 模組
二、遞迴詳解
針對之前的斐波那契數列Fibonacci Sequence
問題,經過不斷思考,運用遞迴、生成器、迴圈等方法,總結出了以下四種方法:
-
遞迴方法1:
# 遞迴方法1 @log_interval def Fibonacci(n): def inner(args): if args == 1 or args == 0: return 1 return inner(args - 1) + inner(args - 2) r = inner(n) return r
-
遞迴方法2:
# 遞迴方法2 @log_interval def Fibonacci(n): def inner(args, a=1, b=1): if args == 0: return a a, b = b, a + b return inner(args - 1, a, b) return inner(n)
-
迴圈方法:
# 非遞迴方法 def Fibonacci(n): a = 1 b = 1 for i in range(n): a, b = b, a + b return a
-
生成器方法
# 生成器方法 def Fibonacci(n): i = 0 def inner(args): a = 1 yield a b = 1 for i in range(args): a, b = b, a + b yield a for i in inner(n): pass return i
為了計算比較下列方法的時間複雜度,設計瞭如下裝飾器來比較四種方法的效率。
def read_dir(dirname): # if os.listdir(dirname) == []: # return for i in os.listdir(dirname): if os.path.isfile(os.path.join(dirname, i)): print(i) if os.path.isdir(os.path.join(dirname, i)): read_dir(os.path.join(dirname, i))
嵌上裝飾器後,我們分別向四個函式傳入了不同的引數,下表是每個方法傳輸的不同引數以及所用時間:
傳入引數 | 返回時間 | |
---|---|---|
遞迴方法1 | 30 | interval: 0.4075314998626709 |
遞迴方法2 | 50 | interval: 0.0010001659393310547 |
迴圈方法 | 50000 | interval: 0.044003963470458984 |
生成器方法 | 50000 | interval: 0.04400515556335449 |
根據上表我們可知,效率方面生成器方法 ≈ 迴圈方法 > 遞迴方法2 >> 遞迴方法1
。
遞迴方法1:將一個問題通過分治法分解成兩個子問題,呼叫函式的次數也必將是最多的,所以其效率理所應當歸為最低;
遞迴方法2:將方法1返回的兩個子問題集合成了一個問題,大幅度地減少了函式的呼叫次數,效能產生了很大的提升,但是由於遞迴自身方法的限制,效率仍然不高;
迴圈方法:利用了和遞迴方法2同樣的思想,有點類似於連結串列頭插法儲存Pre-Node
和Node
的思想,不斷向下滾動生成所需的結果,由於只有一層迴圈,所以效率非常高。
生成器方法:利用剛剛學習的yield
構建生成器的方法,也可以只需要一層迴圈實現斐波那契數列的計算,本質上也屬於迴圈方法,效率和上面的迴圈方法基本一致。
三、shutil 模組
shutil 模組對檔案和檔案集合提供了許多高階操作,特別是提供了支援檔案複製和刪除的函式。
-
拷貝檔案
# `shutil.copy2(old_path, new_path)` shutil.copy2(r'D:\Python\Python Project\day20\lianjia.html', r'D:\Python\Python Project\day21\lianjia.html')
-
拷貝目錄
# shutil.copytree(old_path, new_path, # ignore=shutil.ignore_patterns('*.pyc')) # ignore=shutil.ignore_patterns('*.py') 表示不要所有的py檔案 shutil.copytree(r'D:\Python\Python Project\day21\day09', r'D:\Python\Python Project\day21\day09.bak', ignore=shutil.ignore_patterns('*.py'))
-
刪除目錄(慎用)
# shutil.rmtree(path, ignore_errors=True) # ignore_errors=True 表示無視刪除的提示(比如檔案正在佔用) shutil.rmtree('day09', ignore_errors=True)
-
移動檔案/目錄
# shutil.move(old_path, new_path, copy_function=shutil.copy2)
-
獲取磁碟使用空間
total, used, free = shutil.disk_usage('c:\\') print('當前磁碟共: %iGB, 已使用: %iGB, 剩餘: %iGB' %(total / 1073741824, used / 1073741824, free/1073741824)) # 1073741814 = 1024^3 # %i是一種表十進位制的佔位符和%d基本沒有區別(找到了之後會寫在這裡)
-
壓縮檔案
# shutil.make_archive(compressed_file_path, 'zip', file_path) shutil.make_archive('day09_z', 'zip', 'day09.bak')
-
解壓檔案
# shutil.unpack_archive(compressed_file_path, 'zip', file_path) shutil.unpack_archive('day09_z.zip', 'day09_unz', 'zip')
四、logging 模組
-
日誌的意義
- 用來排除錯誤
- 用來做資料分析
-
日誌的意義——以網路購物商城為例
一個專案需要構建一個數據庫存放足夠重要的內容;而還有一些相對來說沒那麼重要的內容,我們沒必要將它們放入資料庫,這時,本地構建日誌就成了我們的最佳選擇。
如購物商城中:
資料庫:什麼時間買了什麼商品、購物車中放置了哪些商品存入;
本地日誌:使用者登入時間、搜尋記錄、使用者關閉時間、瀏覽商品清單等;
比如我們擁有 10W 客戶,每天有 1W 條購買記錄需要存放在資料庫中,每天就會有10W+ 條和購買相關的資訊由於資料庫容量限制和網路傳輸限制,需要存放在本地日誌中;我們進行資料分析、操作審計、排查BUG等情況下,均需要檢查日誌記錄的情況,所以記錄日誌對於專案來說非常重要;而記錄日誌,就需要 logging 模組。
-
日誌資訊的等級
由於需要記錄的資訊眾多,所以我們必須要對記錄的內容進行重要性排序,logging 模組為我們提供了以下五種重要性:
# 輸出內容是有等級的,重要性從上至下依次升高:預設處理warning級別以上的所有資訊 # logging.debug('debug message') # logging.info('info message') # logging.warning('warning message') # logging.error('error message') # logging.critical('critical message')
logging 模組預設處理
warning
級別以上的所有資訊,而我們可以通過logging.basicConfig(level=logging.DEBUG)
吧重要性調整為DEBUG
等級,調整為其它等級同理。 -
日誌的設定
-
輸出到螢幕
logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s[line : %(lineno)d] -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p') logging.warning('warning test') # 2020-07-18 21:22:00 PM - root - WARNING[line : 66] -03 logging 模組: warning test
-
輸出到檔案
logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s[line : %(lineno)d] -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', filename='tmp.log', level=logging.DEBUG, filemode='a' ) logging.debug('debug test') logging.warning('warning test1') logging.warning('warning test2')
-
同時向螢幕和檔案上輸出
fh = logging.FileHandler('tmp.log', encoding='utf-8') # 定義log的編碼型別和檔案路徑 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] ) logging.warning('warning test1') logging.warning('warning test2') logging.warning('warning test3')
-
定時/定長記錄日誌
import time from logging import handlers # 按照大小做切割,每個日誌1024位元組,每五個替換一次 rh = handlers.RotatingFileHandler('myapp.log', maxBytes=1024, backupCount=5) # 按時間切,按秒切,只記錄距今6s的記錄 th = handlers.TimedRotatingFileHandler(filename='x2.log', when='s', interval=6, encoding='utf-8') sh = logging.StreamHandler() logging.basicConfig( handlers=[rh, sh, th], 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 ) for i in range(19999): time.sleep(0.5) logging.warning('warning test1')
-