这个小程序很简单原本没有记录下来的必要,但在编写过程中又让我学到了一些新的知识,并且遇到了一些不能解决的问题,然后,然后就很有必要记录一下。
这个程序的关键是获取文件大小,本来用 os.path.getsize(path) 就能解决,但是我还想让他用MB、kb这样的单位来显示,并且能显示运行时间,这就又接触到了新知识,最后在在应用计时模块timeit时遇到了一个问题,花了很长时间也没有解决
完整代码如下:
#! 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()
转换大小单位
从网上到的程序是这样的 来源
但是我看不懂,经过研究,把理解的部分注释上去了
#定义一个函数用来将尺寸变为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提供的强大的计时库,不仅使用方便,而且还可以让函数重复运行
测试语句执行时间:
#看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:UsersAdministrator.SC-201605202132AppDataLocalProgramsPythonPython37lib imeit.py", line 237, in repeat return Timer(stmt, setup, timer, globals).repeat(repeat, number) File "C:UsersAdministrator.SC-201605202132AppDataLocalProgramsPythonPython37lib imeit.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:UsersAdministrator.SC-201605202132AppDataLocalProgramsPythonPython37forTest.py", line 10, in <module> 'from __main__ import foo',number=10)#这里要加括号 File "C:UsersAdministrator.SC-201605202132AppDataLocalProgramsPythonPython37lib imeit.py", line 232, in timeit return Timer(stmt, setup, timer, globals).timeit(number) File "C:UsersAdministrator.SC-201605202132AppDataLocalProgramsPythonPython37lib imeit.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:UsersAdministrator.SC-201605202132AppDataLocalProgramsPythonPython37forTest.py", line 9, in <module> work_time=timeit('foo(1,1)','from __main__ import foo(num1,num2)',number=10)#这里要加括号 File "C:UsersAdministrator.SC-201605202132AppDataLocalProgramsPythonPython37lib imeit.py", line 232, in timeit return Timer(stmt, setup, timer, globals).timeit(number) File "C:UsersAdministrator.SC-201605202132AppDataLocalProgramsPythonPython37lib imeit.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:UsersAdministrator.SC-201605202132AppDataLocalProgramsPythonPython37forTest.py", line 9, in <module> work_time=timeit('foo(num1,num2)','num3,num4','from __main__ import foo',number=10)#这里要加括号 File "C:UsersAdministrator.SC-201605202132AppDataLocalProgramsPythonPython37lib imeit.py", line 232, in timeit return Timer(stmt, setup, timer, globals).timeit(number) File "C:UsersAdministrator.SC-201605202132AppDataLocalProgramsPythonPython37lib imeit.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:UsersAdministrator.SC-201605202132AppDataLocalProgramsPythonPython37forTest.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='')
好了