2015-01-31 6 views
1

У меня есть этот скрипт, написанный, который участвует в синтаксическом анализе при работе с большим файлом. Для каждой строки в файле (после некоторых тяжелых манипуляций) мне нужно добавить проверку, чтобы увидеть, соответствует ли она определенным критериям, и если да, добавьте ее в список для дополнительной обработки позже.Постоянная переменная в функции Python

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

Одна из версий этой части сценария может быть:

matchingLines = [] 
def lineProcess(line): 
    global matchingLines 
    if line.startswith(criteria): 
     matchingLines.append(line) 
for line in myFile: 
    # lots of other stuff 
    lineProcess(line) 

Очевидно, что в этом простом примере это не так много боли, чтобы просто сделать проверку в основной функции, а не заморачиваться с какими-либо дополнительными функциями. Но в принципе, мне интересно, какой лучший общий способ делать такие вещи - без использования внешних переменных.

EDIT: Часть причины, по которой я нахожу, что отдельная функция привлекательна, состоит в том, что как только я собрал список строк, я собираюсь использовать их для управления другим внешним файлом, и было бы удобно, чтобы вся операция была завернута в содержащем модуле. Однако я понимаю, что это может быть преждевременная оптимизация.

ответ

3

-то вроде следующего может быть рассмотрено более вещим:

def is_valid_line(line): 
    """Return True if the line is valid, else False.""" 
    return line.startswith(criteria) 

valid_lines = [l for l in myFile if is_valid_line(l)] 

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

valid_lines = (l for l in myFile if is_valid_line(l)) 

Таким образом, чтение файла и строка-проверка будет только на самом деле происходит, когда что-то пытается перебрать valid_lines, а не раньше. Например. В следующем случае:

valid_lines = [l for l in myFile if is_valid_line(l)] 
for line in valid lines: 
    stuff_that_can_raise_exception(line) 

В этом случае, вы прочитали и проверен весь (огромный файл) и иметь полный список проверенных линий, а затем первая строка вызывает ошибку, то время, потраченное подтверждение весь файл тратится впустую. Если вы используете выражение генератора ((x for x in y)) вместо понимания списка ([x for x in y]), то при возникновении ошибки вы еще не подтвердили файл (только в первой строке). Я только упоминаю об этом, потому что я ужасен за то, что не делаю этого чаще сам, и во многих случаях он может принести большой прирост производительности (в ЦП и памяти).

+0

Определенно. Как я писал в ответ на Эве, возможно, я задаю слишком философский вопрос. Я хотел бы иметь систему, которая хорошо масштабируется со сложностью, и в зависимости от задействованных критериев я подозреваю, что такое решение займет у меня только до сих пор. – glarue

+0

Вы можете создать отдельный модуль с вашим собственным классом, который подклассы File, и этот класс эффективно «спрячет» все несоответствующие строки.Но я не уверен, что имеет какое-либо отношение к глобальным переменным - я все еще не совсем понимаю, почему вы думаете, что вам может понадобиться это вообще? Если вы можете привести пример того, как может потребоваться более сложная система, мы можем предложить несколько советов, какие могут помочь архитектура или шаблоны проектирования. –

+0

Да, может быть, я страдаю от случая синдрома «не планируемый-вопрос-вне-спрашивая». Глобальные переменные вступают в игру, потому что все вышеперечисленное происходит внутри функции, и обработка файлов, которые мне нужны для сопоставления, будет происходить вне родительской функции. Конечно, я мог бы заставить эту родительскую функцию вернуть соответствующий список, но это потребует перезаписи многих других вещей. Это вообще помогает? – glarue

1

Вы можете использовать класс и иметь атрибут matching_lines. Но вы можете просто сделать это:

def process_line(line, matching_lines): 
    if line.startswith(criteria): 
     matching_lines.append(line) 

... 

matches = [] 
for line in my_file: 
    # lots of other stuff 
    process_line(line, matches) 
+0

Правильно, спасибо за ответ. Вероятно, мне следовало бы собрать более формальный пример, но я думаю, что я спрашиваю, что это лучший способ сделать это в целом, чтобы учесть все более сложные задачи синтаксического анализа (т. Е. Не просто простую проверку startswith() или что-то еще), не злоупотребляя глобальными значениями – glarue

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