這個小程序很簡單本來沒有記錄下來的必要,但在編寫過程當中又讓我學到了一些新的知識,而且遇到了一些不能解決的問題,而後,而後就頗有必要記錄一下。html
這個程序的關鍵是獲取文件大小,原本用 os.path.getsize(path) 就能解決,可是我還想讓他用MB、kb這樣的單位來顯示,而且能顯示運行時間,這就又接觸到了新知識,最後在在應用計時模塊timeit時遇到了一個問題,花了很長時間也沒有解決python
完整代碼以下:linux
#! python3 #chapter09-test02.py - 找出一個文件夾內的大文件,並打印出大文件的絕對路徑
#-----爲了防止運行時間過長,我把程序設置爲了只檢查前1000個超過size的文件,他們並非最大的1000個 import os,pprint,sys import timeit,time #裝飾器--計算程序運行時間 def colocked_decorator(func): def colock(*args): startTime=timeit.default_timer() result=func(*args) #運行程序 spendTime=timeit.default_timer()-startTime name=func.__name__ #獲取程序名字 arg_str=','.join(repr(arg) for arg in args) #注意不是*args 組成程序參數的字符串 print('[0.7fs] %s(%s) '%(spendTime,name,arg_str),end='') print('%r',result) return result return colock #尋找指定文件夾內的的大文件 #返回包含全部大文件的絕對地址的一個列表 #folder-指定的文件夾地址 #size-閾值,超過這個爲大文件 @colocked_decorator def findBigFile(folder,size): bigFileAbs=[] for foldername,subfolders,filenames in os.walk(folder): #對文件進行遍歷 for filename in filenames: #.getsize(path)必須是完整路徑 fileAbs=os.path.join(foldername,filename) if os.path.getsize(fileAbs)>size and len(bigFileAbs)<100: #fileAbs=os.path.join(foldername,filename) fileAbs=os.path.abspath(fileAbs) bigFileAbs.append(fileAbs) return bigFileAbs #定義一個函數用來將尺寸變爲KB、MB這樣的單位,可是沒有在這個程序中使用 #size-是os.getsize()返回的文件尺寸數值 #is_1024_byte 表明以1024去轉化仍是1000去轉化,默認是1024 #先定義的後綴 SUFFIXES = {1000:['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], 1024:['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']} def humanReadable_size(size,is_1024_byte=True): #mutiple默認是1000 mutiple=1000 if is_1024_byte else 1024 #與for遍歷結合起來,這樣來進行遞級的轉換 for suffix in SUFFIXES[mutiple]: size/=mutiple #直到Size小於能往下一個單位變的數值 if size<mutiple: return '{0:.1f}{1}'.format(size,suffix) raise ValueError('number too large') path='F:\DCIM' size=1000000 #設定的閾值 #先判斷路徑是否存在 if os.path.exists(path): resultList=findBigFile(path,size) pprint.pprint(resultList) else: print('You enter path does not exist') sys.exit()
從網上到的程序是這樣的 來源小程序
可是我看不懂,通過研究,把理解的部分註釋上去了app
#定義一個函數用來將尺寸變爲KB、MB這樣的單位 #size-是os.getsize()返回的文件尺寸數值 #is_1024_byte 表明以1024去轉化仍是1000去轉化,默認是1024 #先定義的後綴 SUFFIXES = {1000:['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], 1024:['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']} def humanReadable_size(size,is_1024_byte=True): #mutiple默認是1000 mutiple=1000 if is_1024_byte else 1024 #與for遍歷結合起來,這樣來進行遞級的轉換 for suffix in SUFFIXES[mutiple]: size/=mutiple #直到Size小於能往下一個單位變的數值 if size<mutiple: return '{0:.1f}{1}'.format(size,suffix) raise ValueError('number too large') #拋出異常
補充函數
這是隔了一段時間又看到的一個計時的方法,以前一直用time.time來計時,最近看到了一篇介紹timeit的文章,居然也很方便,記錄的時候驚訝的發現原來居然也用過timeit,只是遇到了不少問題,果真好記性不如爛筆頭啊學習
參考連接:https://www.cnblogs.com/PrettyTom/p/6657984.html測試
timeit是python提供的強大的計時庫,不只使用方便,並且還可讓函數重複運行spa
測試語句執行時間:.net
#看x=1的執行時間,執行1次(number能夠省略,默認值爲1000000): timeit('x=1', number=1) #看一個列表生成器的執行時間,執行1次: timeit('[i for i in range(10000)]', number=1)
測試函數運行時間:
# timeit(函數名_字符串,運行環境_字符串,number=運行次數) t = timeit('func()', 'from __main__ import func', number=1000) print(t)
另一個重複運行repeat
因爲電腦永遠都有其餘程序也在佔用着資源,你的程序不可能最高效的執行。因此通常都會進行屢次試驗,取最少的執行時間爲真正的執行時間。
from timeit import repeat def func(): s = 0 for i in range(1000): s += i #repeat和timeit用法類似,多了一個repeat參數,表示重複測試的次數(能夠不寫,默認值爲3.),返回值爲一個時間的列表。 t = repeat('func()', 'from __main__ import func', number=100, repeat=5) print(t) print(min(t))
另外,我又學習了計時器的部分信息爲程序增長了一個計算查詢耗時的功能
work_time=repeat(findBigFile(path,1000000), 'from _main_ import findBigFile',number=1,repeat=1) #repeat=1表明運行一輪,number=1表明每輪運行一次,返回一個每次運行時間的列表
但加上以後就出現了錯誤
Traceback (most recent call last): File "C:/Users/Administrator.SC-132/AppData/Local/Programs/Python/Python37/chapter09-test02-判斷文件大小.py", line 45, in <module> 'from _main_ import findBigFile',number=1,repeat=1) File "C:\Users\Administrator.SC-201605202132\AppData\Local\Programs\Python\Python37\lib\timeit.py", line 237, in repeat return Timer(stmt, setup, timer, globals).repeat(repeat, number) File "C:\Users\Administrator.SC-201605202132\AppData\Local\Programs\Python\Python37\lib\timeit.py", line 128, in __init__ raise ValueError("stmt is neither a string nor callable") ValueError: stmt is neither a string nor callable
搞了半天無果後發現 stmt是個變量,覺得找到了題眼,三秒鐘後發出一聲嘆氣後繼續思考,考慮是不是findBigFile有返回值的緣由,遂測試,然而無果
忽然發現是語法的問題,要寫成這樣才行。
from timeit import timeit def foo(): x=1 work_time=timeit('foo()','from __main__ import foo',number=10)#這裏要加引號 print(work_time)
這樣能夠解決上面的錯誤,能運行了,而後我又測試有參數的函數以下
from timeit import timeit def foo(argv1,argv2): #此次有參數 argv1+=argv2 #return argv1 num1=1 num2=1 work_time=timeit('foo(num1,num2)','from __main__ import foo',number=10)#這裏要加括號 print(work_time)
又出現了錯誤
Traceback (most recent call last): File "C:\Users\Administrator.SC-201605202132\AppData\Local\Programs\Python\Python37\forTest.py", line 10, in <module> 'from __main__ import foo',number=10)#這裏要加括號 File "C:\Users\Administrator.SC-201605202132\AppData\Local\Programs\Python\Python37\lib\timeit.py", line 232, in timeit return Timer(stmt, setup, timer, globals).timeit(number) File "C:\Users\Administrator.SC-201605202132\AppData\Local\Programs\Python\Python37\lib\timeit.py", line 176, in timeit timing = self.inner(it, self.timer) File "<timeit-src>", line 6, in inner NameError: name 'num1' is not defined
我突發奇想把timeit()函數改爲了這樣:
work_time=timeit('foo(1,1)','from __main__ import foo',number=10)#直接把值傳進去,不用變量
將程序中的代碼改爲上面調用方式,通過測試能夠運行,只是須要注意假如參數時字符串時,須要注意參數的引號不能與這個函數外部的引號匹配上即:
work_time=timeit('findBigFile("F:\DCIM",1000000)', #這裏要使用雙引號 'from __main__ import findBigFile',number=1)
這樣就行了,而後我想到「沒有定義的變量」這個錯誤是否是因爲from __main__ import foo這裏沒有爲foo指定參數而後我又這樣試了一下:
work_time=timeit('foo(1,1)','from __main__ import foo(num1,num2)',number=10)
然而無效:
Traceback (most recent call last): File "C:\Users\Administrator.SC-201605202132\AppData\Local\Programs\Python\Python37\forTest.py", line 9, in <module> work_time=timeit('foo(1,1)','from __main__ import foo(num1,num2)',number=10)#這裏要加括號 File "C:\Users\Administrator.SC-201605202132\AppData\Local\Programs\Python\Python37\lib\timeit.py", line 232, in timeit return Timer(stmt, setup, timer, globals).timeit(number) File "C:\Users\Administrator.SC-201605202132\AppData\Local\Programs\Python\Python37\lib\timeit.py", line 109, in __init__ compile(setup, dummy_src_name, "exec") File "<timeit-src>", line 1 from __main__ import foo(num1,num2) ^ SyntaxError: invalid syntax
我開始去找return Timer(stmt, setup, timer, globals).timeit(number)這裏面每一個參數的意思,找到了這個:
1) timeit.timeit(stmt='pass', setup='pass', timer=<defaulttimer>, number=1000000) 返回:返回執行stmt這段代碼number遍所用的時間,單位爲秒,float型 參數:stmt:要執行的那段代碼 setup:執行代碼的準備工做,初始化代碼或構建環境導入語句,不計入時間,通常是import之類的 timer:這個在win32下是time.clock(),linux下是time.time(),默認的,不用管 number:要執行stmt多少遍
我以爲這個setup可能有用而後修改代碼:
num4=1 num3=1 work_time=timeit('foo(num1,num2)','num3,num4','from __main__ import foo',number=10)#這裏要加括號 print(work_time)
出現錯誤
Traceback (most recent call last): File "C:\Users\Administrator.SC-201605202132\AppData\Local\Programs\Python\Python37\forTest.py", line 9, in <module> work_time=timeit('foo(num1,num2)','num3,num4','from __main__ import foo',number=10)#這裏要加括號 File "C:\Users\Administrator.SC-201605202132\AppData\Local\Programs\Python\Python37\lib\timeit.py", line 232, in timeit return Timer(stmt, setup, timer, globals).timeit(number) File "C:\Users\Administrator.SC-201605202132\AppData\Local\Programs\Python\Python37\lib\timeit.py", line 176, in timeit timing = self.inner(it, self.timer) File "<timeit-src>", line 3, in inner NameError: name 'num3' is not defined
我有想到是否是能夠像from __main__ import foo同樣去導入變量,
work_time=timeit('foo(num1,num2)','from __main__ import num1', 'from __main__ import num2' ,'from __main__ import foo',number=10)#這裏要加括號
又被摩擦了一次
Traceback (most recent call last): File "C:\Users\Administrator.SC-201605202132\AppData\Local\Programs\Python\Python37\forTest.py", line 11, in <module> ,'from __main__ import foo',number=10)#這裏要加括號 TypeError: timeit() got multiple values for argument 'number'
而後放棄,哈哈,感受一會兒解脫了呢
換個思路解決問題,
使用修飾器來爲這個帶參數的函數測試時間
#裝飾器--計算程序運行時間 def colocked_decorator(func): def colock(*args): startTime=timeit.default_timer() result=func(*args) #運行程序 spendTime=timeit.default_timer()-startTime name=func.__name__ #獲取程序名字 arg_str=','.join(repr(arg) for arg in args) #注意不是*args 組成程序參數的字符串 print('[%0.7fs] %s(%s) '%(spendTime,name,arg_str),end='') print('%r',result) return result return colock
遇到的問題:
1)
Traceback (most recent call last): File "C:/Users/Administrator.SC-201605202132/AppData/Local/Programs/Python/Python37/chapter09-test02-判斷文件大小.py", line 59, in <module> resultList=findBigFile(path,size) TypeError: 'NoneType' object is not callable
我首先去測試函數不修飾時有沒有問題,通過測試沒有,加上修飾器後纔有問題,我就去檢查修飾器,發現了修飾器沒有寫return 修復事後
2) 「並不是在字符格式化期間轉換全部參數」--字符格式化符號沒寫對
Traceback (most recent call last): File "C:/Users/Administrator.SC-201605202132/AppData/Local/Programs/Python/Python37/chapter09-test02-判斷文件大小.py", line 61, in <module> resultList=findBigFile(path,size) File "C:/Users/Administrator.SC-201605202132/AppData/Local/Programs/Python/Python37/chapter09-test02-判斷文件大小.py", line 16, in colock print('[0.7fs] %s(%s) '%(spendTime,name,arg_str),end='') TypeError: not all arguments converted during string formatting
通過檢查是這裏的問題
print('[0.7fs] %s(%s) '%(spendTime,name,arg_str),end='')
應該爲
print('[%0.7fs] %s(%s) '%(spendTime,name,arg_str),end='')
好了