python语言规范

1. lint 
    对你的代码运行pylint。 
pylint是一个在python源代码中查找bug的工具,对于c和c++这样的不那么动态的语言,这些bug通常由编译器来捕获。由于python的动态特性,有些警告可能不对,不过伪告警应该很少。 
优点: 可以捕获容易忽视的错误,例如输入错误,使用未赋值的变量等 
缺点: pylint不完美,要利用其优势,我们有时候需要 a)围绕着它来写代码 b) 抑制其告警 c)改进它 d)忽略它

2. 导入 
    仅对包和模块使用导入 
使用 import x 来导入包和模块 
使用 from x import y,其中x是包前缀,y是不带前缀的模块名 
使用 from x import y as z,如果连个要导入的模块都叫做y或者y太长了

3. 包 
    使用模块的全路径名来导入每个模块 
优点:避免模块名冲突,查找包更容易 
缺点:部署代码变难,因为你必须复制包层次 
结论:所有的新代码都应该用完整包名来导入每个模块,即如下:

1
2
3
4
5
6
7
8
9
10
11
12
#reference in code with complete name
import sound.effects.echo
 
#reference in code with just module name(preferred)
from sound.effects import echo #这样就可以在程序中使用echo,而非 sound.effects.echo 全名来访问模块echo
 
使用模块的全路径名,比如
import sound.effects.echo
而非相对路径,比如
import sound
import sound.effect
import echo

4. 异常 
    异常必须遵守特定的条件: 
(1)触发异常方式 
raise MyException('Error message') 或者 
raise MyException, "Error message" 
而不要使用过时的字符串异常 raise "Error message" 
(2)模块或包应该定义自己的特定于的异常基类,这个基类应该从内建的Exception类继承,模块的异常基类应该叫做Error.

1
2
class Error(Exception):
    pass

 

(3)永远不要使用except:语句来捕获所有异常,也不要捕获 Exception 或者 StandardError,除非你打算重新触发该异常,或者你已经在当前线程的最外层(记得还是要打印一条错误消息) 
(4)尽量减少 try/except块中的代码量,try块的体积越大,期望之外的异常就越容易被触发。这种情况下,try/except块将隐藏真正的错误。 
(5)使用finally自居来执行那些无论try块中有没有异常都应该被执行的代码,例如关闭文件 
(6)当捕获异常时,使用as而不要用逗号,例如

1
2
3
4
try:
    raise Error
except Error as e:
    pass

 

5. 全局变量 
    避免使用全局变量,全局变量是定义在模块级别的变量,导入模块时可能改变模块行为,因为导入模块时会对模块级变量赋值。 
避免使用模块变量,使用类变量来代替。

6. 嵌套/局部/内部类或函数 
    鼓励使用嵌套/本地/内部类或函数。 
类可以定义在方法中,函数或者类中;函数可以定义在方法或函数中。封闭区间中定义的变量对嵌套函数是只读 
优点:允许定义仅用于有效范围的工具类或函数 
缺点:嵌套类或局部类的示例不能被序列化

7. 列表推导 
    列表推导和生成器表达式提供了一种简洁高效的方式来创建列表和迭代器,而不必借助map(), filter()或者lambda() 
优点:简单的列表推导可以比其他的列表创建方法更加清晰简单,生成器表达式可以十分高效,因为他们避免创建整个列表。 
缺点:复杂的列表推导或者生成器表达式可能难以阅读 
因此,适用于简单的情况。每个部分应该单独置于一行:映射表达式,for语句,过滤器表达式,禁止多重for语句或过滤器表达式。复杂情况下还是使用for循环。

8. 默认迭代器和操作符 
    如果类型支持,就使用默认的迭代器和操作符,比如列表,字典以及文件。默认操作符和迭代器简单高效,他们直接表达了操作,没有额外的方法调用。使用默认操作符的函数是通用的,它可以用于支持该操作的任何类型。 
比如:

1
2
3
4
5
for key in adict
if key not in adict
if obj in alist
for line in afile
for k, v in dict.iteritems()

 

9. 生成器 
    按需使用生成器。所谓生成器函数,就是每当他执行一次生成(yield)语句,它就返回一个迭代器,这个迭代器生成一个值。生成值后,生成器函数的运行状态将被挂起,直到下一次生成。 
优点:简化代码,因为每次调用时,局部变量和控制流的状态都会被保存,比起一次创建一系列之的函数,生成器使用的内存小。

10. lambda函数 
    适用于单行函数。lambda在一个表达式中定义匿名函数,常用于为 map()和filter()之类的高阶函数定义回调函数或者操作符。 
    lambda表达式很方便,但是比本地函数更难阅读和调试,没有函数名意味着堆栈跟踪更难理解。由于lambda函数通常只包含一个表达式,因此其表达能力有限。

11. 条件表达式 
    条件表达式是对于if语句的一种更为简洁的句法规则,适用于单行函数。比如 x = 1 if cond else 2

12. 属性 
    访问和设置数据成员时,建议使用属性@property来代替轻量级的访问和设置函数。

13. True/False求值 
    尽可能使用隐式false 
python在布尔上下文中会将某些值求值为false,所有的“空”值都被认为是false。因此,0、False、None、[]、{}都被认为是False 
使用python布尔值的条件语句更易读也不易出错,大部分情况下也更快。比如

1
2
3
4
5
6
应该:
if not x:
    print 'x is an empty list'
不应该:
if x == []:
    print 'x is an empty list'

 

(1)永远不要用==或者!=来比较单件,比如None。使用is或者is not 
(2)注意:当你写下 if x: 时,其实表示的是 if x is not None: 
(3)永远不要用 == 将一个布尔量与false比较,使用 if not x 代替,如果需要区分false和None,应该使用if not x and x is not None 
(4)对于序列(字符串,元组,列表),要注意空序列是false。即 if not seq要好于if not len(seq) 
(5)处理整数时,使用隐式false可能会得不偿失(即不小心将None当做0处理)。可以将一个已知是整型(且不是len()的返回结果)的值与0比较。 
(6)注意'0'(字符串)会被当做true

14. 过时的语言特性 
    尽可能使用字符串方法取代字符串模块,使用函数调用语法取代apply(),使用列表推导,for循环取代 filter(), map(), reduce().

15. 词法作用域 
    嵌套的python函数可以引用外层函数中定义的变量,但是不能对它们进行赋值。变量绑定的解析是使用词法作用域,也就是基于静态的程序文本。对一个块中的某个名称的任何赋值都会导致python将对该名称的全部引用当做局部变量,甚至是赋值前的处理。如果碰到global声明,该名称就会被视作全局变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
i = 4
def foo(x):
    def bar():
        print i
    #....
    #a bunch of code
    #....
    for i in x:
        print i
    bar()
 
foo([1,2,3])
结果输出 1 2 3 3, 而不是 1 2 3 4
x是一个列表,for循环将x中的值依次赋给i,这样对i的赋值就隐式的发生了,
整个foo函数体中的i都会被当做局部变量,包括bar()中的那一个

 

对于上面的例子,按照python的解释性语言,过程化、变量随时生成、随时赋值的特性来看待,就非常容易理解。 
    因为 在foo函数中,执行完 for 循环之后,i变量被赋值了,此时执行bar(),i变量仍然为刚刚的那个值。

16. 线程 
    不要依赖内建类型的原子性。虽然python的内建类型例如字典看上去拥有原子操作,但是在某些情形下它们仍然不是原子的。 
    优先使用Queue模块的Queue数据类型作为线程间数据通信方式,另外使用threading模块机器锁原语。了解条件变量的合适使用方式,这样就可以使用threading.Condition 来取代低级别的锁了。

posted @   农民伯伯-Coding  阅读(602)  评论(0)    收藏  举报
编辑推荐:
· Hangfire Redis 实现秒级定时任务,使用 CQRS 实现动态执行代码
· Android编译时动态插入代码原理与实践
· 解锁.NET 9性能优化黑科技:从内存管理到Web性能的最全指南
· 通过一个DEMO理解MCP(模型上下文协议)的生命周期
· MySQL下200GB大表备份,利用传输表空间解决停服发版表备份问题
阅读排行:
· .NET周刊【4月第1期 2025-04-06】
· 国产的 Java Solon v3.2.0 发布(央企信创的优选)
· 工良出品 | 长文讲解 MCP 和案例实战
· centos停服,迁移centos7.3系统到新搭建的openEuler
· 多年后再做Web开发,AI帮大忙
点击右上角即可分享
微信分享提示