使Python脚本面向对象

gre*_*nie 22 python oop

我正在用Python编写一个应用程序,它将具有许多不同的功能,所以逻辑上我认为最好将我的脚本分成不同的模块.目前我的脚本读入一个文本文件,其中包含已转换为标记和拼写的代码.然后,该脚本将代码重建为一个字符串,其中的空行将在原始代码中显示注释.

我遇到了使脚本面向对象的问题.无论我尝试什么,我似乎无法让程序以与它只是一个脚本文件相同的方式运行.理想情况下,我想要有两个脚本文件,一个包含清理和重建文件的类和函数.第二个脚本只是从命令行中作为参数给出的文件中的另一个文件中的类调用该函数.这是我目前的脚本:

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
Run Code Online (Sandbox Code Playgroud)

按照下面的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()
Run Code Online (Sandbox Code Playgroud)

我仍然想将我的代码分成多个模块.我的程序中的"已清理文件"将在其上执行其他功能,因此清理文件本身应该是一个类吗?

Ale*_*lli 50

要以可测量的速度加速现有代码,请def main():在分配之前添加tokenList,在该4个空格之后缩进所有内容,并在最后放置通常的成语

if __name__ == '__main__':
  main()
Run Code Online (Sandbox Code Playgroud)

(保护实际上并不是必需的,但是这是一个很好的习惯,因为对于具有可重用功能的脚本,它可以从其他模块导入它们).

这与"面向对象"的任何东西都没什么关系:在Python中,将所有实质代码保留在函数中而不是作为顶级模块代码更快.

第二次加速,cleanedInput换成一个列表,即它的第一个任务应该是= [],而且无论你现在在哪里,都要+=使用.append.最后,''.join(cleanedInput)获得最终的结果字符串.这使得您的代码在输入大小(O(N)表示这种情况的正常方式)的函数中采用线性时间,而它当前需要二次时间(O(N squared)).

然后,正确性:continue永远执行后的两个语句.你需要它们吗?continue如果不需要,删除它们(和),如果continue实际需要这两个语句,则删除它们.if diff除非前一个if执行,否则从一开始的测试将会大大失败,因为diff那时将是未定义的.您发布的代码是否有缩进错误,即您发布的内容与实际代码的缩进不一致?

考虑到这些重要的必要增强功能,以及很难看出你在制作这个微小代码OO(和/或模块化)时所追求的优势,我建议澄清缩进/正确性情况,应用我提出的增强功能,以及把它留在那里;-).

编辑:由于OP现在已经应用了我的大部分建议,让我以一种合理的方式跟进一个单独模块中的大多数功能.例如foobar.py,在新文件中,在与原始脚本相同的目录中(或在其中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
Run Code Online (Sandbox Code Playgroud)

然后你的主要脚本变成了:

import sys
import foobar

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

if __name__ == '__main__':
  main()
Run Code Online (Sandbox Code Playgroud)

  • 要稍微扩展一下Alex的观点:在Python中,字符串是不可变的.`s + ='abc'`使用附加的'abc`创建一个全新的`s`副本.因此,如果您正在构建一个带连接的长字符串,那么您将一遍又一遍地复制不断增长的字符串.将项添加到列表(或使用`StringIO`模块)然后在最后执行单个`join`可以避免这种情况. (8认同)