Making a Python script Object-Oriented
我正在用python编写一个应用程序,它将有很多不同的函数,所以从逻辑上讲,我认为最好将脚本拆分为不同的模块。当前,我的脚本在一个文本文件中读取,该文件包含已转换为标记和拼写的代码。然后,脚本将代码重新构造为一个字符串,其中的注释将出现在原始代码中。
不过,我在编写面向对象的脚本时遇到了问题。无论我尝试什么,我似乎都不能让程序像只运行一个脚本文件那样运行。理想情况下,我想要两个脚本文件,一个包含类和函数,用于清理和重建文件。第二个脚本只需从另一个文件中的类调用函数,该文件作为命令行中的参数提供。这是我当前的脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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 += ' ' if diff == 1: cleanedInput += ' ' else: cleanedInput += ' ' * diff prevLine = lineNo continue cleanedLine = line.split(':', 1)[1].strip() cleanedInput += cleanedLine + ' ' print cleanedInput |
在遵循下面的alex martelli建议之后,我现在有了下面的代码,它提供了与原始代码相同的输出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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(' ') if diff == 1: cleanedInput.append(' ') else: cleanedInput.append(' ' * diff) prevLine = lineNo continue cleanedLine = line.split(':', 1)[1].strip() cleanedInput.append(cleanedLine + ' ') print cleanedInput if __name__ == '__main__': main() |
不过,我还是想将代码拆分为多个模块。我的程序中的"已清理文件"将对其执行其他功能,因此,自然地,已清理文件本身应该是类?
为了有效地加速现有代码,在分配给
1 2 | if __name__ == '__main__': main() |
(保护实际上不是必需的,但是这是一个好习惯,因为对于具有可重用函数的脚本,它使它们可以从其他模块导入)。
这与"面向对象"没有什么关系:在Python中,将所有重要的代码保存在函数中,而不是作为顶级模块代码,这样做只会更快。
第二个加速,把
那么,正确性:在
考虑到这些重要的需要增强的功能,以及很难看出您在使这个小代码OO(和/或模块化)方面所追求的优势,我建议澄清缩进/正确性情况,应用我提出的增强功能,并将其保留在这个位置;-)。
编辑:由于OP现在已经应用了我的大部分建议,所以让我用一种合理的方法将大部分功能划分到单独模块中的一个类中。在新文件中,例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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(' ' * (diff if diff>1 else diff+1)) prevLine = lineNo else: cleanedLine = token_of(line) cleanedInput.append(cleanedLine + ' ') return cleanedInput |
然后,您的主脚本变为:
1 2 3 4 5 6 7 8 9 | import sys import foobar def main(): thefile = foobar.FileParser(sys.argv[1]) print thefile.cleaned_input() if __name__ == '__main__': main() |
当我进行这种特殊的重构时,我通常从第一个文件中的初始转换开始。步骤1:将功能移到新类中的方法中。步骤2:添加下面的魔术调用使文件像脚本一样运行:
1 2 3 4 5 6 7 8 9 10 11 | 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]) |
如果呈现的代码都是代码,就不要添加任何类!!
你的代码太简单了!!OOP方法会增加不必要的复杂性。
但如果仍然不行。把所有代码都放到函数中。
1 2 3 4 5 | def parse_tokenized_input(file): tokenList = open(file, 'r') cleanedInput = '' prevLine = 0 #rest of code |
在结束添加:
1 2 | if __name__ == '__main__': parse_tokenized_input(sys.argv[1]) |
如果代码工作正常,请将函数的def放到新文件中(以及所有需要的导入!)MyMODYLY.PY
现在您的脚本将是:
1 2 3 4 | from mymodule.py import parse_tokenized_input if __name__ == '__main__': parse_tokenized_input(sys.argv[1]) |
哦,为您的函数和模块想出更好的名称(模块应该有通用名称)。
您可以通过创建一个函数并将您的所有逻辑都放在它里面来逃脱惩罚。但是,对于完全的"对象定向",您可以这样做:
ps-您发布的代码在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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)) |