2011-01-03 3 views
0

Ich unterrichte Python seit einiger Zeit und habe es noch nie programmiert. Ich habe gerade ein einfaches Backup-Programm geschrieben, das den Fortschritt jeder einzelnen Datei während des Kopierens ausgibt. Ich habe eine Funktion geschrieben, die die Puffergröße bestimmt, so dass kleinere Dateien mit einem kleineren Puffer kopiert werden und größere Dateien mit einem größeren Puffer kopiert werden. Die Art und Weise, wie ich den Code eingerichtet habe, scheint nicht sehr effizient zu sein, da es eine if-Schleife gibt, die zu einer anderen if-Schleife führt, die vier Optionen erzeugt und alle dieselbe Funktion mit unterschiedlichen Parametern aufrufen.Gibt es eine bessere Möglichkeit, verschiedene Parameter mit if-Anweisungen in eine Funktion einzugeben?

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') 

Gibt es einen besseren Weg, um das zu erreichen, was ich tue? Entschuldigung, wenn der Code schlecht oder schwer zu verstehen ist. Ich wollte niemanden bitten, alle 120 Zeilen meines schlecht geschriebenen Codes durchzulesen, also habe ich einfach die beiden Funktionen isoliert. Danke für jede Hilfe.

Antwort

2

Ich glaube, dass Sie auf dem richtigen Weg sind. Eine Lösung für Ihr Problem ist das Speichern der Parameter in Variablen.

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) 

Oder eine andere Lösung wenn Sie die normalen Standardargumente halten wollen:

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) 

ein wenig Extranote, etwas wie folgt aus:

if len(filestocopy.keys()) == 0: 
    return None 

könnte auch so geschrieben werden:

if not filestocopy: 
    return 

Die Schleife selbst könnte dies vereinfacht werden:

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) 

Und die keys() benötigt nie wirklich, wenn Wörterbücher Iterieren wie das Standardverhalten ist :)

Also, die folgenden Zeilen werden alle die gleichen Ergebnisse erhalten:

keys = list(some_dict) 
keys = some_dict.keys() 
keys = list(some_dict.keys()) 
keys = list(some_dict.iterkeys()) 
1

Einige Hinweise, zuerst:

  • statt len(filestocopy.keys()), können Sie einfach tun len(filestocopy)
  • Bevorzugen for key in filestocopy.iterkeys() über for key in filestocopy.keys()

Sie so etwas wie versuchen könnte:

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) 

Ich weiß nicht, welche Argumente Ihre ‚Kopie‘ -Funktion nimmt, aber man konnte tu etwas stattdessen:

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) 

Hier sollte "WHATEVER_SIZE" offensichtlich w ersetzt werden ie die Puffergröße für kleinere Listen oder was auch immer der Standardwert sein soll.

Die Grundidee besteht darin, Ihre Funktionsargumente vor Sie zu Variablen zu loopen und dann diese Variablen in Ihrem Funktionsaufruf zu verwenden.:)

0

Nun sieht es aus wie Sie die gleiche Funktion sind Aufruf 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) 

mit einer unterschiedlichen Anzahl von Argumenten. Warum brauchst du das If/Else hier? Es ist nicht sehr klar.

1

Die Antworten von WoLpH und Sapph sind ungefähr richtig. Hier ist eine zufällige Python Vereinfachung Sie für Ihre durchschnittliche Berechnung tun können, mit generator expressions:

average_size = sum(int(filestocopy[k]['size']) for k in filestocopy)/len(filestocopy) 
+0

Keine Notwendigkeit für ein Listenverständnis hier. Ein einfacher Generator (d. H. Ohne das '[]') würde genauso gut funktionieren :) +1 sowieso – Wolph

+0

Oh, cool! Bearbeitet. Vielen Dank! –

0

Du hast einen großen Beispielcode und es war schwierig zu folgen. Aber was Sie aus dem Titel Ihrer Frage fragen (interpretieren) ist: "Wie übergibt man normalerweise eine variable Anzahl von Argumenten" an den Funktionsaufruf eines Pythons? Dann ist die Antwort, indem man Listen/Tupel oder Wörterbücher übergibt.

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) 

Beachten Sie, dass beim Übergeben des Containers (Liste/Tupel) und eines Wörterbuchs das erstere dem späteren vorausgehen sollte.

Verwandte Themen