有没有更好的方法将不同的参数输入到if语句的函数中?

时间:2011-01-03 03:49:17

标签: python

我一直在教自己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行代码,所以我只是将这两个函数分开了。谢谢你的帮助。

5 个答案:

答案 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)和字典时,前者应该在后者之前。