任何人都应该知道的介绍:为什么要强调写规范?其实这不是为了“美丑”,而是为了更高的效率(代码阅读、开发、维护)和更便捷的合作(全球通用标准)。现在的学生不管往哪个方向走,都要做“写代码”的工作。遗憾的是,很多朋友并没有意识到,花1小时去理解代码编写标准,可以让自己节省100+小时的代码编写时间。代码规范的魅力在于,它确实把问题简单化了,我们不需要把它当作一个标准,也不需要引起争议。在本文中,我们主要以python为例,以pep8为主要参考资料,分三个层次进行讨论。本文分为三个层次:不要关注这些,你写的根本不是代码,本质是尊重程序的逻辑,一些规范我会忽略,多思考而不关注这些,你写的根本不是代码1/2。看我两年前的代码importtkinterimporttkinter.messageboxdefmessage_box(error_content):top=tkinter.Tk()#************top.withdraw()#****实现主要隐藏顶部的窗口。update()#*********需要更新一下txt=tkinter.messagebox.showinfo("prompt",error_content)top.destroy()returntxt上面是用python的tkinter做一个桌面应用,看似乎不是问题?大问题,比如项目逻辑/设计架构,确实很难通过这几行代码看出来;但是,以上几行代码的书写习惯,反映出一个人的思维还不够成熟:注释不用写成#****,没必要更新。这是无稽之谈。前面不是update()函数吗?("Prompt",error_content)中间要有空格txt=tkinter左右两边要有空格如果我现在写的话,我会这样实现:importtkinterfromtkinterimportmessageboxasmsgdefshow_message_box(error_content):"""Pipereggnest:输入错误信息,messagebox显示信息(一起来看看:欢迎来到Piper蛋窝~)"""tk=tkinter.Tk()tk.withdraw()tk.update()txt=msg.showinfo("Prompt",error_content)tk.destroy()returntxt如上:我修正了一些小问题,比如是否有空格等,但这不是重点。我把函数名从message_box改成了show_message_box,因为message_box看起来像名词,不是动词(Toperformatask),项目结构复杂后,我们可能会有很多函数、类、实例。如果不区分动名词,可能会把自己搞糊涂,还得回源码查,浪费很多时间。注释(这个函数负责什么)放在"""comment"""中,这样我们调用它的时候解释器和InelliSense会自动解释,如图2/2所示。最基础:缩进、命名和空格朋友们,如果你在写代码的时候连缩进、命名和空格这三点都没有注意到,那么恭喜你,这篇文章很有可能让你更上一层楼。见过一个刚学c的大一新生,在机房VC6中一个一个地敲字符:#includeintmain(){inta=5,b=7,c;printf("a=%d,b=%d,c=%d",a,b,c);return0;}很明显,这孩子的代码真的只是“输入计算机的字符”,他没有逻辑和水平他心中的计划。这段代码是死的,不是活的。我只是添加了一些空格和回车来解释为什么这些缩进、名称和空格使代码成为真正的代码。#includeintmain(){inta=5,b=7,c;printf("a=%d,b=%d,c=%d",a,b,c);return0;}如上:我把{}独立出来,把里面的代码块缩进,说明这些代码是函数main()内部的逻辑。我加了空格,比如把a=5改成a=5,是的,因为程序员也是人,看得见的东西也是要看的。我在#include和intmain()之间加了一个空行,因为这两个是两个东西:前者负责引入io标准库,后者负责执行逻辑。写代码的时候,不要吝啬用空行来区分不同的逻辑和任务。上面的讨论是不是太基础了?下面以python及其官方文档pep8为例,看看官方更多体现程序逻辑、增强代码可读性的建议。如果下次有人给他看他写的“死代码”,你就先把这篇文章扔给他,让他改正!这些规范的本质是尊重程序的逻辑1/4。缩进和空格:体现逻辑缩进。原则问题?这当然只是个玩笑。在python中,推荐使用4个空格进行缩进。我在玩kddcup的时候(官方启动工具包里)看到有2个空格用于缩进。我觉得无所谓,关键是你要在项目中统一。此外,缩进用于显示程序结构,如果您的结构不是包含,只是换行符,那么缩进4个空格也很愚蠢。如下。#推荐foo=long_function_name(var_one,var_two,var_three,var_four)#orfoo=long_function_name(var_one,var_two,var_three,var_four)#orfoo=long_function_name(var_one,var_two,var_three,var_four)#ordeflong_var_name(wo,var_three,var_four):print(var_one)#stupidfoo=long_function_name(var_one,var_two,var_three,var_four)#stupiddeflong_function_name(var_one,var_two,var_three,var_four):print(var_one)为什么?下面以deflong_function_name为例,你注意到了吗:print(var_one)应该是deflong_function_name的内部结构,所以肯定比deflong_function_name多了一个缩进,但是var_one、var_two、var_three参数是deflong_function_name的一部分,与deflong_function_name同级别的函数参数与函数内部结构对齐时,容易让人混淆。因此,您只需要创建一个区分即可。至于你是多加两个空格还是少两个空格都无所谓(除非你的组织有具体规定),只要你和其他人一眼就能看出逻辑结构即可。应该在二元运算符之前或之后换行吗?另外pep8还推荐了operator的位置,之前确实没注意到。#否:运营商离他们的操作收入很远=(gross_wages+taxable_interest+(dividends-qualified_dividends)-ira_deduction-student_loan_interest)#Yes:运营商与operandsicome很容易匹配=(gross_wages+taxable_interest+(dividends-qualified_dividends)-ira_deduction-student_loan_interest)另外,为了防止编译错误,我会在换行符后面加上\\,对换行键进行转义。income=(gross_wages\+taxable_interest\+(dividends-qualified_dividends)\-ira_deduction\-student_loan_interest)在这种情况下似乎没有必要这样做。拒绝无意义的空格Yes:spam(ham[1],{eggs:2})No:spam(ham[1],{eggs:2})Yes:ifx==4:printx,y;x,y=y,xNo:如果x==4:打印x,y;x,y=y,x以上是PetPeeves中的建议。显然,过于松散的结构不利于我们阅读和看到逻辑。这是所有编程语言共有的一个习惯,值得养成。函数变量默认值#yesdefcomplex(real,imag=0.0):returnmagic(r=real,i=imag)#nodefcomplex(real,imag=0.0):returnmagic(r=real,i=imag)同上,在定义默认值时,我们鼓励您删除=两边的空格。#Yesdefmunge(sep:AnyStr=None):...defmunge(input:AnyStr,sep:AnyStr=None,limit=1000):...#Nodefmunge(input:AnyStr=None):...defmunge(input:AnyStr,limit=1000):...不过,如上,值得注意的是,如果定义了函数的数据类型(如AnyStr),需要提醒开发者注意区分,并且不要删除=周围的空格。2/4importYes:importosimportsysNo:importsys,os#Yesi=i+1submitted+=1x=x*2-1hypot2=x*x+y*yc=(a+b)*(a-b)#Noi=i+1submitted+=1x=x*2-1hypot2=x*x+y*yc=(a+b)*(a-b)关于import有几个规范,这里强调一下,新手可能有“Bad习惯”:将不相关的库放在一个导入下。你在画什么?无意义的。比如上面,sys其实和os是没有包含关系的,那我们为什么要吝啬这行import呢?而且放在一起,也不利于formatter帮我们整理写。3/4为变量和函数选择一个好的命名约定不同的公司/组织,尤其是大公司,会有自己的命名约定。对于java,我记得最常用的应该是“驼峰”命名:publicvoidprintUserName(intindex){...}在python中,鼓励各种常见形式的命名,比如:printUserNameprint_user_name我想大家都是python中最常用的是下划线+小写的形式。Descriptive:NamingStylesofpep8中有一个注释,非常好笑:Capitalized_Words_With_Underscores(ugly!)WhyisCapitalized_Words_With_Underscores"ugly"?我觉得是信息冗余:单词之间用下划线或者大写字母隔开,两者都用,确实不够简洁优雅。“私有”变量在C++或者Java中,我们都会接触到private等概念。初学者可能会疑惑:变量为什么要分为private、public、protected?Python让初学者避免了这部分可能出现的混淆,但它并没有去掉私有变量等功能。我觉得这就是pythonic的体现。而且现在的语言都有这种趋势,比如go,就把首字母大小写敏感的变量限制为private和shared,简洁大方,统一社区开发规范。对于python,我们在变量前加上两个下划线,它就变成私有的了。为了项目规范和安全,私有变量不能被外部调用。我写了一个程序如下。如上,直接调用Foo.__a或foo.__b会产生AttributeError错误。但是python给了一个“后门”,你仍然可以通过_类名__变量名来调用私有变量。4/4尊重“人的思维”#YesiffooisnotNone:#NoifnotfooisNone:如上,可能新手会认为not...is的结构逻辑是反的,很有意思,虽然它的作用与不是完全一样。还是那句话,程序员也是人,大家都喜欢简单明了的逻辑。除非是非常高明的技巧,否则没必要玩文字游戏,降低效率。#Yestry:value=collection[key]exceptKeyError:returnkey_not_found(key)else:returnhandle_value(value)#Notry:#太宽泛了!returnhandle_value(collection[key])exceptKeyError:#WillalsocatchKeyErrorraisedbyhandle_value()returnkey_not_found(key)如上,使用trycatch时,我们要捕获KeyError,所以不要在try中进行其他操作。为什么?如果handle_value()本身是错误的,我们很难通过handle_value(collection[key])捕捉到它自己的错误,因为它和collection[key]可能的错误混淆了#yesdeffoo(x):ifx>=0:returnmath.sqrt(x)else:returnNonedefbar(x):ifx<0:returnNonereturnmath.sqrt(x)#Nodeffoo(x):ifx>=0:returnmath.sqrt(x)defbar(x):ifx<0:returnreturnmath.sqrt(x)同上,当x小于0时,不能求平方根,自然不能输入math.sqrt().这里我们应该让程序更清晰,虽然我们知道如果一个函数什么都不做,它会返回None,但是不要写成returnNone。用pep8的话来说,我们应该在return语句中保持一致。我会忽略一些规范,更多地考虑每行最多1/3个字符?我拒绝。我们知道pep8期望我们每行最多79个字符。我认为对于像我这样的开发人员来说真的没有必要。此外,我已经阅读了很多不遵守此标准的优秀开源框架。原因很简单,我们的生产环境不一样。我喜欢大字体,我只有一台没有桌子的小笔记本电脑。很多朋友都有好几块屏/加长屏,而我却只能把一个小本本的显示屏竖着分成两块。如下所示。不管是79个字符还是109个字符,我的编辑器都无法在一行中显示出来,所以这个规范对我来说意义不大。也许在开发python标准库的时候会用到。但是不是现在。2/3注释文件标准?在我对pep8和pep257的复议中,对标注方式进行了规范,如下。defcomplex(real=0.0,imag=0.0):"""形成一个复数。关键字参数:real--实部(默认0.0)imag--虚部(默认0.0)"""ifimag==0.0andreal==0.0:returncomplex_zero...我不是很感兴趣。原因:我记得在pyCharm中,默认的注释不是这样的,说明该标准不是唯一可以使用的特定标准。我认为有必要讨论这个问题。比如MkDocs会帮我们自动将评论编译成文档发布到网上,所以我们在要使用MkDocs的时候,先了解一下MkDocs的规范。以上是thu-ml/tianshou的源码,其注释是用markdown写的。如果你访问文档,你会发现文档是根据源代码注释自动生成的。惊人的。这才是“码农”应该具备的美德:懒惰,不做重复的动作,有可能就自动化。3/3多看好项目好过看规范文档。最后只说不练假把戏。在我看来,多看优秀的代码和项目,有意识地关注master的写作规范和项目结构如何安排,比只看pep8有意义多了。愿你们都变得更强大。欢迎关注公众号:吹笛蛋巢,回复微信加我微信。欢迎点赞,点击观看,鼓励我。