2016-08-23 5 views
0

Предположим, у меня есть многострочная строка, которая может содержать строки, состоящие из одного имени файла. Я хочу напечатать каждую строку в строке, если строка не является именем файла (определяется здесь как «.txt»), и в этом случае я хочу напечатать каждую строку в этом файле, если строка в этом файле не является имя файла и т.д.Какой рекурсивный подход - лучший дизайн?

Мой первоначальный подход заключается в использовании вспомогательной функции следующим образом:

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) 

Но имея передать line_sep в вспомогательную функцию только передать его обратно, кажется, безвкусный.

Так что я попробовал такой подход, который использует только одну функцию:

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) 

Это имеет неявный необходимый аргумент (либо s или file_path, но не оба), но так как пользователь функции будет использовать только один вид (s=) это может быть не слишком kludgey. Также кажется немного странным с точки зрения пользователя, что line_sep является первым аргументом.

Какой подход является лучшим дизайном? Есть ли другой подход, который я должен рассмотреть?

+6

Я бы пошел с первым вариантом - функция не должна иметь взаимоисключающих входов, если вы можете ей помочь. – mgilson

+0

Так как у этого есть 6 upvotes, если вы могли бы добавить его в качестве ответа, я могу его принять. –

ответ

0

Чтобы избежать передач параметра line_sep, вы можете определить вспомогательную функцию внутри рекурсивной функции:

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) 
+1

Так как это рекурсивная функция, каждый раз, когда вызывается 'deep_print', она создаст копию' deep_print_helper', которая не требуется –

2

Ваш вопрос не должен быть связан с вещим способом для достижения этой цели. Это связано с дизайном, независимо от языка. Если вы спросите меня среди двух подходов, я пойду с 1. Но лучший способ достичь - через класс, имеющий ваши функции внутри него. В Python вы можете сделать это нравится:

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

Хороший вопрос об этом является общим вопросом дизайна. Я изменил название и формулировку, чтобы отразить это. –

+0

Метод '__init__' должен иметь аргумент' string', а не аргумент 'file_path' согласно требованиям в OP. Также мы можем исключить неэффективность параметров метода 'line_sep', сохраняя' line_sep' в переменной экземпляра. –

+0

Я не модифицировал ваш код. Я просто перенес свои функции в класс. Теперь вы можете проверить это. Я изменил его на основе обновлений, сделанных вами –

0

Ваши требования не могут позволить, но с помощью str.splitlines бы сделать вещи немного менее сложным. В том же напрасно, есть ли причина, по которой исходный файл не открывается как часть рекурсии (т. Е. Вместо передачи строки в deep_print, вы можете передать путь file_)? Если эти два ограничения можно снять, вы можете сделать что-то вроде следующего:

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() для l в s.splitlines()]' не будет возвращать список строк, а вместо слов в каждой строке. –

+0

Кроме того, OP требует специального разделителя строк –

+1

На самом деле мне очень нравится 's.splitlines()'. Это позволяет мне полностью исключить аргумент 'line_sep' в моем приложении, что является ответом на этот вопрос SO:' http://stackoverflow.com/questions/39093525/how-to-join-incorporate-splitted-lines- с заменой-data-from-a-file-in-the'.Да, было бы проще передать имя файла 'deep_print', но вопрос имеет требование к строковому аргументу. –

Смежные вопросы