使Python脚本面向对象
我正在用Python编写一个应用程序,它将有很多不同的函数,所以从逻辑上讲,我认为最好将我的脚本分成不同的模块。目前,我的脚本读取一个文本文件,其中包含已转换为标记和拼写的代码。然后,脚本将代码重新构造为字符串,在原始代码中注释所在的位置有空行使Python脚本面向对象,python,oop,Python,Oop,我正在用Python编写一个应用程序,它将有很多不同的函数,所以从逻辑上讲,我认为最好将我的脚本分成不同的模块。目前,我的脚本读取一个文本文件,其中包含已转换为标记和拼写的代码。然后,脚本将代码重新构造为字符串,在原始代码中注释所在的位置有空行 def main(): tokenList = open(sys.argv[1], 'r') cleanedInput = [] prevLine = 0 for line in tokenList:
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()
但是,我在使脚本面向对象时遇到了一个问题。无论我做什么尝试,我似乎都无法让程序像运行单个脚本文件一样运行。理想情况下,我希望有两个脚本文件,其中一个包含清理和重建文件的类和函数。第二个脚本只需从另一个文件中的类调用函数,该文件作为命令行中的参数给定。这是我当前的脚本:
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:将功能移动到新类中的方法中。步骤2:添加 下面的魔术调用使文件再次像脚本一样运行:
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])
class LineCleaner:
def清洁文件(文件名):
cleanInput=“”
prevLine=0
对于打开的行(文件名为'r'):
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
cleaner=LineCleaner()
cleaner.cleanFile(sys.argv[1])
要显著加快现有代码的速度,请在分配到标记列表之前添加def main():
,在这4个空格之后缩进所有内容,并在最后放入常用习惯用法
if __name__ == '__main__':
main()
(实际上不需要保护,但这是一个好习惯,因为对于具有可重用函数的脚本,它使它们可以从其他模块导入)
这与“面向对象”没有什么关系:在Python中,将所有实质性代码保存在函数中比作为顶级模块代码更快
第二次加速,更改cleanedInput
到一个列表中,即它的第一个赋值应该是=[]
,无论您现在有+=
,请使用.append
。最后,'.join(cleanedInput)
获取最终结果字符串。这使得您的代码采用线性时间作为输入大小的函数(O(N)
是表达这一点的正常方式),而当前代码采用二次时间(O(N平方)
)
然后是正确性:continue
后面的两条语句永远不会执行。你是否需要它们?删除它们(以及continue
),如果不需要,则删除continue
,如果实际需要这两条语句。如果不执行前一个if
,则以if diff
开始的测试将显著失败,因为diff
将没有定义。您发布的代码是否有缩进错误,即,您发布的内容的缩进是否与实际代码的缩进不同
考虑到这些重要的必要增强,并且很难看出您在制作这个小代码OO(和/或模块化)时追求的优势,我建议澄清缩进/正确性情况,应用我提出的增强,并就此为止;-)
编辑:由于OP现在已经应用了我的大部分建议,让我用一种合理的方法将大部分功能划分到单独模块中的类。在新文件中,例如foobar.py
,与原始脚本位于同一目录中(或网站包中,或系统路径上的其他地方),放置以下代码:
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
然后,您的主脚本将变成:
import sys
import foobar
def main():
thefile = foobar.FileParser(sys.argv[1])
print thefile.cleaned_input()
if __name__ == '__main__':
main()
您可以创建一个函数并将所有逻辑放在其中。但是,要实现完全的“面向对象”,您可以执行以下操作:
ps-您发布的代码在continue
行上有一个bug-它总是被执行,最后两行永远不会执行
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))
如果呈现的代码都是代码,就不要添加任何类
你的代码太简单了!!
OOP方法会增加不必要的复杂性
但如果还是不行。
将所有代码放入函数例如
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
现在,您的脚本将是:
from mymodule.py import parse_tokenized_input
if __name__ == '__main__':
parse_tokenized_input(sys.argv[1])
哦,为您的函数和模块想出更好的名称(模块应该有通用名称)。假设您有您想要的对象。你会如何使用它?换句话说,你想要什么语法?在这种情况下,我会把输入文件看作是对象。清洁过程是我希望能够对所述对象执行的功能。考虑到这一点,我希望采用for循环,并在我的输入文件类中使用cleaning函数。但是,clean()
和arg
仍然未定义。抱歉,在我准备好之前点击提交按钮。另外,我刚刚找到了代码示例widgit。sighHa,两个强迫症患者试图同时清理同一个帖子。这就像是一个疯狂的欧亨利故事,也许是“三博士的礼物”。稍微扩展一下Alex的一点:在Python中,字符串是不可变的s+=“abc”
制作了一份全新的s
副本,附加了abc
。因此,如果您正在使用串联构建一个长字符串,那么您正在一次又一次地复制一个不断增长的字符串。将项目追加到列表(或使用StringIO
模块),然后执行单个联接