我希望这个问题适合stackoverflow。如果没有,我会马上删除这个问题。
我刚刚编写了我的第一个python程序。我们的想法是你可以发出一个命令,并将它并行发送到几个服务器。
这仅用于个人教育目的。该计划有效!我真的想在python上变得更好,因此我想问下列问题:
我有一个很好的编程背景,但我花了很长时间才开发出适合PHP的样式(PEAR编码标准,知道使用什么工具以及何时使用)。
源(一个文件,92行代码)
答案 0 :(得分:10)
通常情况下,句子:
结尾之后的内容是在一个单独的行中(也不要在它之前添加空格)
if options.verbose:
print ""
而不是
if options.verbose : print ""
如果你要迭代它,你不需要检查列表的len
if len(threadlist) > 0 :
for server in threadlist :
...
是多余的,更“可读”(python足够聪明,不能遍历空列表):
for server in threadlist:
...
另外一个更''pythonistic'是使用列表的理解(但肯定是一个值得商榷的意见)
server = []
for i in grouplist : servers+=getServers(i)
可以缩短为
server = [getServers(i) for i in grouplist]
答案 1 :(得分:7)
在卸载任何批评之前,首先让我祝贺你的第一个Python程序正常运行。从一种语言转移到另一种语言可能是一件苦差事,不断摸索语法问题并通过不熟悉的库进行搜索。
引用最多的风格指南是PEP-8,但这只是一个指南,至少有一部分被忽略了......不,我的意思是认为不适用于某些特定情况而对所有应有的尊重指南作者和贡献者: - )。
我无法将它与PHP进行比较,但与其他Python应用程序相比,很明显您正在遵循其他语言的样式约定。我并不总是同意其他开发人员说你必须做的很多事情,但随着时间的推移,我认识到为什么使用约定有助于传达应用程序正在做的事情,并将帮助其他开发人员帮助你。
<小时/> 提高异常,而不是字符串。
raise 'Server or group ' + sectionname + ' not found in ' + configfile
变为
raise RuntimeError('Server or group ' + sectionname + ' not found in ' + configfile)
<小时/> 在'if'或'for'结尾处的':'之前没有空格,并且不要在同一行上放置多个语句,并且要在运算符周围放置空格。为对象使用变量名称并坚持使用
i
和j
作为循环索引变量(比如我们熟练的FORTRAN前辈):
for i in grouplist : servers+=getServers(i)
变为:
for section in grouplist: servers += getServers(section)
<小时/> 可以对容器进行内容测试,而无需考虑其长度:
while len(threadlist) > 0 :
变为
while threadlist:
和
if command.strip() == "" :
变为
if command.strip():
<小时/> 拆分元组通常不会放在语句左侧的括号中,命令逻辑有点复杂。如果没有args那么“.join(...)将是一个空字符串:
(options,args) = parser.parse_args() if options.verbose : print "floep 0.1" command = " ".join(args) if command.strip() == "" : parser.error('no command given')
变为
options, args = parser.parse_args() if options.verbose: print "floep 0.1" if not args: parser.error('no command given') command = " ".join(args)
<小时/> 一个python for循环有一个不寻常的'else'子句,如果循环遍历所有元素而没有'break',则执行该子句:
for server in threadlist : foundOne = False if not server.isAlive() : ...snip... foundOne = True if not foundOne : time.sleep(0.010)
变为
for server in threadlist: if not server.isAlive(): ...snip... break else: time.sleep(0.010)
<小时/> 获取行列表然后将它们连接在一起有点长篇大论:
result = proc.readlines() strresult = '' for line in result : strresult+=line self.result = strresult
变为
self.result = proc.read()
<小时/> 您的库使用情况良好,请查看子进程模块,它是更新的。
您的数据类型没问题。
你会得到很多其他的东西: - )
答案 2 :(得分:5)
Python中不推荐使用字符串异常,所以这一行:
if not config.has_section(sectionname):
raise 'Server or group ' + sectionname + ' not found in ' + configfile
应该重做这样的事情:
if not config.has_section(sectionname):
raise ConfigNotFoundError(
"Server or group" + sectionname + "not found in" + configfile)
class ConfigNotFoundError(Exception):
pass
[编辑在评论中反映了dangph的建议]
这是更多的代码行,但它对未来的升级更好。
为了便于阅读,可以这样:
parser.add_option('-q','--quiet',action="store_false", help="Display only server output", dest="verbose", default=True)
可以像这样重写:
parser.add_option('-q',
'--quiet',
action="store_false",
help="Display only server output",
dest="verbose",
default=True)
你可能更喜欢另一种分割方法调用的方法,但想法是长行很难读。
您还应阅读PEP 8以了解Python风格。
答案 3 :(得分:3)
通常,为了重复使用,我们会执行以下操作,从程序中的第48行开始
def main():
config = ConfigParser.RawConfigParser()
etc.
if __name__ == "__main__":
main()
这只是一个起点。
完成此操作后,您会发现main()实际上是两部分:解析命令行界面并完成工作。然后你想重构一下这样的东西。
def serverWork(group,...):
servers = getServers(group)
etc.
def main():
config = ConfigParser.RawConfigParser()
if command.strip() == "":
parser.error('no command given')
else:
serverWork( options.group, options.etc., ... )
现在,您已将实际工作提升到此模块中的函数。您的serverWork函数现在可以被其他程序或脚本轻松重用。