我一直在教自己Python一段时间,我以前从未编程过。我刚刚写了一个基本的备份程序,它在复制时写出每个文件的进度。我编写了一个函数来确定缓冲区大小,以便使用较小的缓冲区复制较小的文件,并使用较大的缓冲区复制较大的文件。我现在设置代码的方式看起来效率不高,因为有一个if循环然后导致另一个if循环,创建四个选项,并且它们都只是用不同的参数调用相同的函数。
import os
import sys
def smartcopy(filestocopy, dest_path, show_progress = False):
"""Determines what buffer size to use with copy()
Setting show_progress to True calls back display_progress()"""
#filestocopy is a list of dictionaries for the files needed to be copied
#dictionaries are used as the fullpath, st_mtime, and size are needed
if len(filestocopy.keys()) == 0:
return None
#Determines average file size for which buffer to use
average_size = 0
for key in filestocopy.keys():
average_size += int(filestocopy[key]['size'])
average_size = average_size/len(filestocopy.keys())
#Smaller buffer for smaller files
if average_size < 1024*10000: #Buffer sizes determined by informal tests on my laptop
if show_progress:
for key in filestocopy.keys():
#dest_path+key is the destination path, as the key is the relative path
#and the dest_path is the top level folder
copy(filestocopy[key]['fullpath'], dest_path+key,
callback = lambda pos, total: display_progress(pos, total, key))
else:
for key in filestocopy.keys():
copy(filestocopy[key]['fullpath'], dest_path+key, callback = None)
#Bigger buffer for bigger files
else:
if show_progress:
for key in filestocopy.keys():
copy(filestocopy[key]['fullpath'], dest_path+key, 1024*2600,
callback = lambda pos, total: display_progress(pos, total, key))
else:
for key in filestocopy.keys():
copy(filestocopy[key]['fullpath'], dest_path+key, 1024*2600)
def display_progress(pos, total, filename):
percent = round(float(pos)/float(total)*100,2)
if percent <= 100:
sys.stdout.write(filename + ' - ' + str(percent)+'% \r')
else:
percent = 100
sys.stdout.write(filename + ' - Completed \n')
有没有更好的方法来完成我正在做的事情?很抱歉,如果代码评论不佳或难以遵循。我不想让别人阅读我写得不好的所有120行代码,所以我只是将这两个函数分开了。谢谢你的帮助。
答案 0 :(得分:2)
我相信你走在正确的轨道上。解决问题的一个方法是将参数保存在变量中。
def smartcopy(filestocopy, dest_path, show_progress = False):
"""Determines what buffer size to use with copy()
Setting show_progress to True calls back display_progress()"""
#filestocopy is a list of dictionaries for the files needed to be copied
#dictionaries are used as the fullpath, st_mtime, and size are needed
if len(filestocopy.keys()) == 0:
return None
#Determines average file size for which buffer to use
average_size = 0
for key in filestocopy.keys():
average_size += int(filestocopy[key]['size'])
average_size = average_size/len(filestocopy.keys())
#Smaller buffer for smaller files
if show_progress:
progress_callback = lambda pos, total: display_progress(pos, total, key)
else:
progress_callback = None
#Bigger buffer for bigger files
if average_size < 1024*10000: #Buffer sizes determined by informal tests on my laptop
buffer = None
else:
buffer = 1024 * 2600
for key, value in filestocopy.iteritems():
#dest_path+key is the destination path, as the key is the relative path
#and the dest_path is the top level folder
copy(value['fullpath'], dest_path+key, buffer, callback=progress_callback)
如果你想保留正常的默认参数,可以使用其他解决方案:
def smartcopy(filestocopy, dest_path, show_progress = False):
"""Determines what buffer size to use with copy()
Setting show_progress to True calls back display_progress()"""
#filestocopy is a list of dictionaries for the files needed to be copied
#dictionaries are used as the fullpath, st_mtime, and size are needed
if len(filestocopy.keys()) == 0:
return None
#Determines average file size for which buffer to use
average_size = 0
for key in filestocopy.keys():
average_size += int(filestocopy[key]['size'])
average_size = average_size/len(filestocopy.keys())
#Smaller buffer for smaller files
kwargs = {}
if show_progress:
kwargs['callback'] = lambda pos, total: display_progress(pos, total, key)
#Bigger buffer for bigger files
if average_size >= 1024*10000: #Buffer sizes determined by informal tests on my laptop
kwargs['buffer'] = 1024 * 2600
for key, value in filestocopy.iteritems():
#dest_path+key is the destination path, as the key is the relative path
#and the dest_path is the top level folder
copy(value['fullpath'], dest_path+key, **kwargs)
一点额外的注意事项,如下:
if len(filestocopy.keys()) == 0:
return None
也可以这样写:
if not filestocopy:
return
循环本身可以简化为:
for key, value in filestocopy.iteritems():
#dest_path+key is the destination path, as the key is the relative path
#and the dest_path is the top level folder
copy(value['fullpath'], dest_path+key, **kwargs)
迭代字典时,keys()
从未真正需要,因为这是默认行为:)
因此,以下几行都会得到相同的结果:
keys = list(some_dict)
keys = some_dict.keys()
keys = list(some_dict.keys())
keys = list(some_dict.iterkeys())
答案 1 :(得分:1)
一些注意事项,首先:
len(filestocopy.keys())
len(filestocopy)
,而不是for key in filestocopy.iterkeys()
for key in filestocopy.keys()
<{1}} 您可以尝试以下方式:
callback = None
if show_progress:
callback = lambda pos, total: display_progress(pos, total, key)
if average_size < 1024*10000:
for key in filestocopy.keys():
copy(filestocopy[key]['fullpath'], dest_path + key, callback)
else:
for key in filestocopy.keys():
copy(filestocopy[key]['fullpath'], desth_path + key, 1024 * 2600, callback)
我不知道你的'复制'功能需要什么参数,但你可以做一些事情:
callback = None
buffer_sz = 1024 * 2600 if average_size >= 1024*10000 else WHATEVER_SIZE
if show_progress:
callback = lambda pos, total: display_progress(pos, total, key)
for key in filestocopy.keys():
copy(filestocopy[key]['fullpath'], dest_path + key, buffer_sz, callback)
这里,“WHATEVER_SIZE”显然应该替换为较小列表的缓冲区大小,或者无论默认值是什么。
基本思想是在循环之前初始化函数参数,变量,然后在函数调用中使用这些变量。 :)
答案 2 :(得分:1)
WoLpH和Sapph的答案是正确的。以下是使用generator expressions进行平均计算的随机Python简化:
average_size = sum(int(filestocopy[k]['size']) for k in filestocopy)/len(filestocopy)
答案 3 :(得分:0)
看起来你正在调用相同的函数copy
if show_progress:
for key in filestocopy.keys():
copy(filestocopy[key]['fullpath'], dest_path+key, 1024*2600,
callback = lambda pos, total: display_progress(pos, total, key))
else:
for key in filestocopy.keys():
copy(filestocopy[key]['fullpath'], dest_path+key, 1024*2600)
具有不同数量的参数。为什么你需要if / else。这不是很清楚。
答案 4 :(得分:0)
您提供了一个巨大的示例代码,很难遵循。但是你从问题的标题中要求(解释)的是“如何通常将可变数量的参数传递给python的函数调用?”然后答案是传递列表/元组或词典。
def fun(a, *b, **c):
print a
for item in b:
print item
for k,v in c:
print k,v
a = 42
b = [1,2,3]
c = {'a':'1','b':2,'c':True}
fun(a,b,c)
请注意,当传递容器(list / tuple)和字典时,前者应该在后者之前。