2016-08-23 3 views
0

Angenommen, ich habe eine mehrzeilige Zeichenfolge, die Zeilen enthalten kann, die aus einem einzigen Dateinamen bestehen. Ich möchte jede Zeile in der Zeichenfolge drucken, es sei denn, die Zeile ist ein Dateiname (hier definiert als '.txt'). In diesem Fall möchte ich jede Zeile in dieser Datei drucken, es sei denn, die Zeile in dieser Datei ist a Dateinamen usw.Welcher rekursive Ansatz ist ein besseres Design?

Mein erster Ansatz ist eine Hilfsfunktion wie folgt zu verwenden:

def deep_print_helper(file_path, line_sep): 
    with open(file_path) as f: 
     text = f.read() 
     return deep_print(text, line_sep) 

def deep_print(s, line_sep): 
    lines = s.split(line_sep) 
    for l in lines: 
     if l.endswith('.txt'): 
      deep_print_helper(l, line_sep) 
     else: 
      print(l) 

Aber mit nur line_sep an die Hilfsfunktion zu übergeben es passieren zurück scheint wieder unelegant.

So habe ich versucht, einen Ansatz, der nur eine Funktion verwendet:

def deep_print(line_sep, s='', file_path=''): 
    if file_path: 
     with open(file_path) as f: 
      s = f.read() 
    lines = s.split(line_sep) 
    for l in lines: 
     if l.endswith('.txt'): 
      deep_print(line_sep, file_path=l) 
     else: 
      print(l) 

Diese implizite erforderliches Argument hat (entweder s oder file_path aber nicht beide), aber da der Benutzer der Funktion nur eine Form verwenden (s=) kann es nicht zu klucky sein. Aus der Sicht des Benutzers erscheint es auch ein wenig seltsam, dass line_sep das erste Argument ist.

Welcher Ansatz ist ein besseres Design? Gibt es einen anderen Ansatz, den ich berücksichtigen sollte?

def deep_print(s, line_sep): 

    def deep_print_helper(file_path): 
     with open(file_path) as f: 
      text = f.read() 
      return deep_print(text, line_sep) 

    lines = s.split(line_sep) 
    for l in lines: 
     if l.endswith('.txt'): 
      deep_print_helper(l) 
     else: 
      print(l) 
+6

Ich würde mit der ersten Variante gehen - Eine Funktion sollte nicht gegenseitig ausschließende Eingänge haben, wenn Sie es helfen können. – mgilson

+0

Da dies 6 upvotes hat, wenn Sie es als Antwort hinzufügen könnten, kann ich es akzeptieren. –

Antwort

0

die line_sep Parameter übergeben Um zu vermeiden, können Sie die Hilfsfunktion innerhalb der rekursiven Funktion definieren. Es hängt mit dem Design zusammen, unabhängig von der Sprache. Wenn Sie mich unter den zwei Ansätzen fragen, werde ich mit 1 gehen. Aber der bessere Weg, um zu erreichen ist über Klasse mit Ihren Funktionen darin. In Python kann tun Sie es mögen:

class DeepPrint(object): 
    def __init__(self, file_path): 
     DeepPrint._deep_print_helper(file_path) 

    @staticmethod 
    def _deep_print_helper(file_path): 
     with open(file_path) as f: 
      return DeepPrint._deep_print(f) 

    @staticmethod 
    def _deep_print(f): 
     for l in f.readlines(): 
      if l.endswith('.txt'): 
       DeepPrint._deep_print_helper(l) 
      else: 
       print(l) 
+1

Da es sich um eine rekursive Funktion handelt, wird jedes Mal, wenn 'deep_print' aufgerufen wird, eine Kopie von 'deep_print_helper' erstellt, die nicht benötigt wird. –

2

Ihre Frage sollte nicht in Bezug auf Pythonic Weg, dies zu erreichen:

+1

Gut, dass dies eine allgemeine Designfrage ist. Ich habe den Titel und die Formulierung geändert, um das zu berücksichtigen. –

+0

Die '__init__' -Methode sollte ein' string'-Argument haben, kein 'file_path'-Argument je nach Anforderung in OP. Außerdem können wir die Ungleichmäßigkeit der "line_sep" -Methodenparameter eliminieren, indem wir "line_sep" in einer Instanzvariablen speichern. –

+0

Ich habe Ihren Code nicht geändert. Ich habe gerade Ihre Funktionen in die Klasse verschoben. Sie können es jetzt überprüfen. Ich habe es basierend auf den Updates von Ihnen geändert –

0

Ihre Anforderungen an das nicht zulassen, aber str.splitlines verwenden würde die Dinge etwas weniger kompliziert. Gibt es aus dem gleichen Grund einen Grund, warum die Originaldatei nicht als Teil der Rekursion geöffnet wird (d. H. Anstatt eine Zeichenkette in deep_print zu übergeben, könnten Sie einen Dateipfad übergeben)? Wenn diese beiden Einschränkungen aufgehoben werden können, könnten Sie etwas wie folgt tun:

def deep_print(file_path): 
    with open(file_path) as f: 
     s = f.read() 
    for line in [l.strip() for l in s.splitlines()]: 
     if line.endswith('.txt'): 
      deep_print(line) 
     else: 
      print(line) 
+0

'[l.strip() für l in s.splitlines()]' wird keine Liste der Zeilen, sondern Wörter in jeder Zeile. –

+0

OP erfordert auch benutzerdefinierte Zeilentrennzeichen –

+1

Eigentlich mag ich wirklich die 's.splitlines()'. Damit kann ich das 'line_sep'-Argument vollständig in meiner Anwendung weglassen, was eine Antwort auf diese SO-Frage ist:' http://stackoverflow.com/questions/39093525/how-to-join-incorporate-split-lines- with-replacing-data-from-a-file-in-the'.Ja, es wäre einfacher, einen Dateinamen an 'deep_print' zu übergeben, aber die Frage hat die String-Argument-Anforderung. –

Verwandte Themen