Создание Python script Объектно-ориентированный

Я пишу приложение на Python, у которого будет много разных функций, поэтому логически я думал, что лучше всего разделить мой script на разные модули. В настоящее время мой script читает в текстовом файле, который содержит код, который был преобразован в токены и письма. Затем script восстанавливает код в строку с пустыми строками, где комментарии были бы в исходном коде.

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

import sys

tokenList = open(sys.argv[1], 'r')
cleanedInput = ''
prevLine = 0

for line in tokenList:

    if line.startswith('LINE:'):
        lineNo = int(line.split(':', 1)[1].strip())
        diff = lineNo - prevLine - 1

        if diff == 0:
            cleanedInput += '\n'
        if diff == 1:
            cleanedInput += '\n\n'
        else:
            cleanedInput += '\n' * diff

        prevLine = lineNo
        continue

    cleanedLine = line.split(':', 1)[1].strip()
    cleanedInput += cleanedLine + ' '

print cleanedInput

Следуя совету Alex Martelli ниже, теперь у меня есть следующий код, который дает мне тот же результат, что и исходный код.

def main():
    tokenList = open(sys.argv[1], 'r')
    cleanedInput = []
    prevLine = 0

    for line in tokenList:

        if line.startswith('LINE:'):
            lineNo = int(line.split(':', 1)[1].strip())
            diff = lineNo - prevLine - 1

            if diff == 0:
                cleanedInput.append('\n')
            if diff == 1:
                cleanedInput.append('\n\n')
            else:
                cleanedInput.append('\n' * diff)

            prevLine = lineNo
            continue

        cleanedLine = line.split(':', 1)[1].strip()
        cleanedInput.append(cleanedLine + ' ')

    print cleanedInput

if __name__ == '__main__':
    main()

Я все равно хотел бы разделить мой код на несколько модулей. У "очищенного файла" в моей программе будут выполняться другие функции, поэтому, естественно, очищенный файл должен быть классом по своему усмотрению?

Ответ 1

Чтобы ускорить ваш существующий код, добавьте def main(): перед назначением tokenList, отложите все после этого 4 пробела и в конце положите обычный idiom

if __name__ == '__main__':
  main()

(Хранитель на самом деле не нужен, но, тем не менее, хорошая привычка, поскольку для скриптов с многократно используемыми функциями он делает их импортируемыми из других модулей).

Это не имеет ничего общего с "объектно-ориентированным": он просто быстрее, в Python, сохраняет весь ваш существенный код в функциях, а не как код модуля верхнего уровня.

Второе ускорение, измените cleanedInput на список, т.е. его первое назначение должно быть = [], а где бы вы ни находились +=, вместо этого используйте .append. В конце, ''.join(cleanedInput), чтобы получить окончательную итоговую строку. Это приводит к тому, что ваш код принимает линейное время в зависимости от размера ввода (O(N) является нормальным способом выражения), в то время как в настоящее время он принимает квадратичное время (O(N squared)).

Затем правильность: два оператора сразу после continue никогда не выполняются. Вам они нужны или нет? Удалите их (и continue), если не нужно, удалите continue, если эти два утверждения действительно необходимы. И тесты, начинающиеся с if diff, потерпят неудачу, если предыдущий if не был выполнен, потому что diff будет undefined. Имеет ли ваш код как опубликованный, возможно, ошибки отступов, т.е. Является отступом того, что вы разместили, отличным от того, что было в вашем фактическом коде?

Учитывая эти важные необходимые улучшения и тот факт, что трудно понять, какую выгоду вы преследуете при создании этого крошечного кода OO (и/или модульного), я предлагаю уточнить ситуацию с отступом/правильностью, применяя усовершенствования, которые я использую предложил и оставил на нем; -).

Изменить: поскольку OP теперь применил большинство моих предложений, позвольте мне проследить один разумный способ убрать большую часть функциональности для класса в отдельном модуле. В новом файле, например foobar.py, в том же каталоге, что и исходный script (или в site-packages или в другом месте на sys.path), поместите этот код:

def token_of(line):
  return line.partition(':')[-1].strip()

class FileParser(object):
  def __init__(self, filename):
    self.tokenList = open(filename, 'r')

  def cleaned_input(self):
    cleanedInput = []
    prevLine = 0

    for line in self.tokenList:
        if line.startswith('LINE:'):
            lineNo = int(token_of(line))
            diff = lineNo - prevLine - 1
            cleanedInput.append('\n' * (diff if diff>1 else diff+1))
            prevLine = lineNo
        else:
            cleanedLine = token_of(line)
            cleanedInput.append(cleanedLine + ' ')

    return cleanedInput

Ваш основной script затем станет просто:

import sys
import foobar

def main():
    thefile = foobar.FileParser(sys.argv[1])
    print thefile.cleaned_input()

if __name__ == '__main__':
  main()

Ответ 2

Когда я делаю этот конкретный рефакторинг, я обычно начинаю с начального преобразования в первом файле. Шаг 1: переместите функциональность в метод в новом классе. Шаг 2: добавьте волшебный вызов ниже, чтобы снова запустить файл как script:

class LineCleaner:

    def cleanFile(filename):
        cleanInput = ""
        prevLine = 0
        for line in open(filename,'r'):         
           <... as in original script ..>

if __name__ == '__main__':
     cleaner = LineCleaner()
     cleaner.cleanFile(sys.argv[1]) 

Ответ 3

Вы можете уйти от создания функции и вставить в нее всю свою логику. Для полной "объектной" ориентации вы можете сделать что-то вроде этого:

ps - у вашего опубликованного кода есть ошибка в строке continue - он всегда выполняется, и последние две строки никогда не будут выполняться.

class Cleaner:
  def __init__(...):
    ...init logic...
  def Clean(self):
    for line in open(self.tokenList):
      ...cleaning logic...
    return cleanedInput

def main(argv):
  cleaner = Cleaner(argv[1])
  print cleaner.Clean()
  return 0

if '__main__' == __name__:
  sys.exit(main(sys.argv))

Ответ 4

Если представленный код - это весь код Просто не добавляйте класс!

Ваш код слишком просто для этого! ООП добавит ненужную сложность.

Но если все-таки будет. Включите весь код, например.

def parse_tokenized_input(file):
    tokenList = open(file, 'r')
    cleanedInput = ''
    prevLine = 0
    #rest of code

в конце добавить:

if __name__ == '__main__':
    parse_tokenized_input(sys.argv[1])

Если код работает корректно, установите def функции в новый файл (и весь необходимый импорт!) например. mymodyle.py

ваш script теперь будет:

from mymodule.py import parse_tokenized_input

if __name__ == '__main__':
        parse_tokenized_input(sys.argv[1])

О, и подумайте о лучшем имени для вашей функции и модуля (модуль должен иметь общее имя).