Python语言规范
一、Lint
定义:pylint是一个在Python源代码中查找bug的工具,c与c++中这些bug通常用编译器来捕获,由于Python语言的动态性,有些警告可能不对,不过误报应该很少。
优点:可以很容易捕获忽视的错误。
缺点:pylint不完美,需要围绕着他来写代码,抑制告警,改进或者忽略。
结论:pylint抑制不准确的告警,设置注释来实现:
dict='something awful'#Bad Idea pylint:disable=redefined-builtin
pyllint的警告是一个数字编号和一个符号来标识的,在编写新代码或者更新已有代码时对警告进行医治,推荐使用符号来标识。如果警告的标识符不能够见名知意。增加详细解释。
使用pylint--list-msgs来获取pylint警告列表。
使用pylint --help-msg=C6409,,获取更多关于特定消息的更多信息。
相比较之前使用的pylint:disable-msg,推荐使用pylint:disable
要抑制参数未使用的警告,可以使用"_"下划线作为参数标识符,或者在参数名钱加unused_ 遇到不能够改变参数名的情况,可以用个在函数开头提到他们来消除警告。eg:
def foo(a,unused_b,unused_c,d=None,e=None):
_=d,e
return a
二、导入
导入时不要使用相对名称,即使模块在同一个包中,也要使用完整包名,这能避免无意间导入一个包两次。
import sound.effects.echo
from sound.effects import echo
三、异常
允许使用异常但是需小心
定义:异常是一种跳出代码块的正常控制流来处理错误或者其他异常条件的方式。
结论:异常必须遵守特定条件
1、像这样触发异常raise MyException("Error message")或者raise MyException不要使用两个参数的形式(raise MyException,"Error message")或者过时的字符串异常(raise "Error message").
2、模块或包应该定义自己特定域的异常基类 ,这个基类应该从内建的Exception类继承,模块的异常基类应该叫做Error
class Error(Exception):
pass
3、永远不要使用except语句来捕获所有异常,也不要捕获Exception或者StandardError,除非要重新触发异常,或者已经在当前线程的最外层。在异常这方面,Python非常宽容,except真的会捕获包括Python语法错误在内的任何错误,使用except很容易隐藏真正的bug。
4、尽量减少try/except块中的代码量,try块的体积越大,期望之外的异常就越容易被触发,这种情况下,try/except块将隐藏真正的代码错误。
5、使用finally子句来执行哪些无论try块中有没有异常都应该执行的代码,这对于清理资源非常的有用,如开关文件。
6、当捕获异常时,使用as而不要使用逗号。
四、全局变量
避免全局变量
定义:定义再木块级的变量。
优点:偶尔有用。
缺点:导入时可能改变模块行为,因为代入模块时会对模块级变量赋值。
结论:避免使用全部变量,用局部变量来代替,但是有些例外。
1、脚本默认选项。
2、模块集常量,例如PI=3.14159,常量应该全大写,用下划线连接。
3、有时候用全局变量来缓存值或者作为函数返回值很有用。
4、如果需要,全局变量应该仅在内部可以使用,并通过模块级的公共函数来访问。
五、嵌套/局部/内部类或函数
建议使用嵌套/本地/内部类和函数
定义:类可以定义在方法,函数或者类中,函数可以定义在方法或者函数中,封闭区间中定义的变量嵌套函数是只读的。
优点:允许定义仅用于有效范围的工具和函数。
缺点:嵌套类或者局部类的实例不能序列化pickled
结论:推荐使用。
六、列表推导 list comprehensions
可以在简单的情况下使用
定义:列表推导与生成器表达式提供了一种简单高效的方式来创建列表和迭代器,而不必借助mao(),filter()或者lamba
优点:简单的列表推导可以比其他的列表创建方法更加的清晰简单,生成器表达式可以十分高效,因为他们避免创建整个列表。
缺点:适用于简单情况,每个部分应该单独一行:映射表达式,for语句,过滤器表达式,禁止多重for语句或过滤器表达式,复杂情况下推荐使用循环
七、默认迭代器和操作符
如果类型支持,就使用默认迭代器和操作符,比如列表,字典以及文件等。
定义:容器类型,像字典和列表,定义了默认的迭代器和关系测试操作符(in ,not in)
优点:more操作符和迭代器简单高效,他们直接表达了操作,没有额外的方法调用,使用默认操作符的函数是通用的,它可以用于支持该操作的任何类型。
缺点:没办法通过阅读方法名来区分对象的类型如:has_key意味着字典。
八、生成器
按需使用生成器
定义:每当执行一次生成yield语句,就返回一个迭代器,这个迭代器生成一个值,生成值后,生成器函数的运行状态就能被挂起,直到下次生成。
优点:简化代码,因为每次调用时,局部变量和控制流的状态都会被保存,比起一次创建一些列值的函数,生成器使用的内存更少。
九、Lambda函数
适用于单行函数
定义:与语句相反,Lambda在一个表达式中定义匿名函数,常用语map和filter之类的高阶函数或者操作符。
优点:方便
缺掉:比本地函数更难阅读和调试,没有函数名意味着堆栈更加难理解,由于Lambda函数通常只包含一个表达式故表达力有限。
结论:适用于单行函数,如果代码超过60-80个字符,最好还是定义成常规嵌套函数,对于常见的操作符,如乘法操作符使用operator模块中的函数代替Lambda函数,如推荐使用operator.mul而非lambda x,y:x*y
十、条件表达式
适用于单行函数
定义:条件表达式是对于if语句一种更为简短的句法x=1 if cond else 2.
优点:比if语句更加简短和方便
缺点:比if语句难以阅读,如果表达式很长难以确定条件
结论:适用于单行函数,在其他情况下,推荐使用完整的if 语句
十一、默认参数值
适用于大部分情况
定义:在函数参数列表的最后指出变量的值,如def foo(a,=0)如果调用foo时只带一个参数,则b被设为0,如果带两个参数则b的值等于第二个参数。
结论:建议使用,不要再函数或者方法定义中使用可变对象作为默认值。
十二、属性
访问和设置数据成员时,通常会使用简单,轻量的访问和设置函数,建议使用属性来代替。
定义“一种用于包装方法调用的方式,当运算量不大,它是获取和设置属性的标准方式。
优点:通过小鼠简单的属性访问时样式的get和set方法的调用,可读性提高,允许惰性的计算,用Pythonic的方式来继续维护类的接口,就性能而言,当直接访问变量是合理的,添加访问方法就显得琐碎和无意义,使用属性可以绕过这个问题,将来也课可以在不破坏接口的情况下将访问方法加上。
缺点:属性是在get和set方法声明后指定,这需要使用者在接下来的代码中注意:set和get是用于属性的,必须继承自object类,可能隐藏比如操作符重载之类的副作用,继承有时令人困惑。
结论:在新的代码中使用属性,只读属性应该用@property装饰器创建,如果自雷没有覆盖属性,那么属性的继承性可能看上去不明显,因此使用者必须确保访问方法简介被调用,以保证子类中的重载方法被属性调用。使用模板设计模式。
待续......