【精华】编写高质量的python程序的91个建议

浏览: 1997

1.理解pythonic(python化)的概念

  •   美胜丑,显胜隐,简胜杂,杂胜乱,平胜陡,疏胜密(以最小,最明显的逻辑单元来写方法)
  •   找到简单问题的一个方法,最好是唯一的方法(正确的解决之道)
  •   难以解释的实现,源自不好的主意;如有非常 棒的主意,它的实现肯定易于解释(一个需求过来,先看自己给自己在逻辑上走的通)
  •   交换变量使用a,b = b,a
  •   使用with 语句来做为python资源的安全关闭文件描述符
  •   使用formate代替%s 等字符串格式化操作
  •   包和模块的命名采用小写,单数,而且短小
  •   包通常仅作为命令空间,如果包含空的__init__.py文件

 

2. 编写pythonic代码

  •   好好修炼内功,从以下几个方面出发
  •   不要害怕过长的变量名
  •   避免使用容易引起混淆(每个func都要明确的指明方法的做用,不要是使用大而范的命名)
  •   避免只用大小写来区分不同的对象
  •   全面掌握python提供的所有特性,包括语言特性与库特性:
  •   python 2.x doc
  •   深入学习比较公认的pythonic的代码,比如Flask,gevent和requests等
  •  查看如下的代码库
  •   非常高质量的代码库

3.理解python与c语言的不同之处

  • python的底层都是用c语言实现的
  • 关于缩进与{} ,如果使用pycharm来写代码,记得将Tab与4个space 空格符相等,这样可以很方便的实现代码的格式化,另外,一定要将space空格显示出来,这样才能很清晰的看到空白处是制表符还是一个空格,关于如果调,请参考我的这篇文章舒服的pycharm设置
  • ‘ 与” ,在c or C# 之中,’ ‘代表的是单个字符,”” 这个里面代表的是字符串,在python之中,单引号与双引号没有明显的区别。
  • 三元操作符 “?:” ,python下是没有三元操作符的,不过可以很方便的写成 x if c else y
  • switch … case ,python之中没有c语言之中分支语句,不过python里面有一个更好的实现方式
def f(x):
return {
0:'you input is zero',
1:'you input is one ',
2:'you input is two'
}.get(x,"i don't know what you are input")

使用dict 实现值的映射,其实这里面不仅仅可以输入一个返回值 ,也可以直接返回python的一等公民:函数

def fp(x):
return {
0:lambda y:y+1,
1:lambda y:y+2,
2:lambda y:y+3
}.get(x,lambda y:y)(x)

当然,函数可以映射,那class更是可以了。

4.在代码中添加适当的注释。

5.通过适当加添加空行使代码布局更为优雅,合理。

  • 在一组代码表达完一个完整的思路之后,应该使用空白行进行间隔
  • 尽量保持上下文语义的易理解性
  • 避免过长的代码
  • 不要为了保持水平对齐而使用多余的空格。

6.编写函数的4个原则

  • 原则1 函数设计要尽量短小,嵌套层次不要太深
  • 原则2 函数声明应该做到合理,简单,易于使用
  • 原则3 函数参数设计应该考虑向下兼容,或者提供参数的默认值
  • 原则4 一个函数只做一件事,尽量保证函数语句粒度的一致性

7.将常量集中到一个文件里面

  • 通过命令风格来提醒使用者该变量的意义为常量,如果常量名所有字母大写,用下划线来链接各个单词
  • 通过自定义的类实现常量功能。

8.利用assert语句来发现问题

断言(assert)在很多语言中是存在的,它主要为调试程序服务。

assert expression1 [‘,’ expression2]

如果 expression1 的值是假的时候,则会出现异常信息

9.数据交换值的时候不推荐使用中间变量。

之前大家一般都会使用中间变量来交换值,现在推荐直接交互。比如

x,y = y,x

那我们更深入一点,为什么会快呢。

一般情况下,python表达式的计算顺序都是从左到右的,但是遇到表达式赋值的时候,表达式右边的操作数(优先级)要先于表达式左边的操作数计算。因些表达式expr3,expr4 = expr1,expr2 的计算优先顺序是

expr1 ,expr2 -> expr3 ,expr4

表达式右边在内存中创建元组,计算时不用重复创建对象,只需要将标识符重新分配就可以达到交换值的目的。这里我们分析一下字节码:

import dis

def swap_third():
a = 1
b = 2
c = a
a = b
b = c
#print a,b

def swap_two():
a = 1
b = 2
a,b = b,a
#print a,b

print dis.dis(swap_two)
print '================'
print dis.dis(swap_third)

输出:

 12           0 LOAD_CONST               1 (1)
3 STORE_FAST 0 (a)

13 6 LOAD_CONST 2 (2)
9 STORE_FAST 1 (b)

14 12 LOAD_FAST 1 (b)
15 LOAD_FAST 0 (a)
18 ROT_TWO
19 STORE_FAST 0 (a)
22 STORE_FAST 1 (b)
25 LOAD_CONST 0 (None)
28 RETURN_VALUE
None
================
4 0 LOAD_CONST 1 (1)
3 STORE_FAST 0 (a)

5 6 LOAD_CONST 2 (2)
9 STORE_FAST 1 (b)

6 12 LOAD_FAST 0 (a)
15 STORE_FAST 2 (c)

7 18 LOAD_FAST 1 (b)
21 STORE_FAST 0 (a)

8 24 LOAD_FAST 2 (c)
27 STORE_FAST 1 (b)
30 LOAD_CONST 0 (None)
33 RETURN_VALUE
None

我们查看标号为18的动作:这里的指令ROT_TWO主要作用是交换栈的最顶层元素,它比执行一个Load_Fast 和 Store_Fast 要快。

10,充分利用Lazy evaluation的特性

惰性计算指的是仅仅在需要真正需要执行的时候才计算表达式的值,充分利用Lazy evaluation的带来的好处主要体现在以下两个方面。

1) 避免不必要的计算,带来性能上的提升。

对于python中的条件表达式if x and y ,在x 为 false 的情况下 y表达式的值将不再计算。而于if x or y,当x的值为true的时候将直接返回,不再计算y的值。因此编码中应该充分利用这一特性。

2) 节省空间,使得无限循环的数据结构成为可能。python中最典型的就是yield 生达器表达式了。它仅每次需要的时候才会返回相应的计算值 。

两个例子一个经典的斐波那契數列,一个是读取文件中使用的

def fab(max):
n, a, b = 0, 0, 1
while n < max:
yield b
# print b
a, b = b, a + b
n = n + 1


def read_file(fpath):
BLOCK_SIZE = 1024
with open(fpath, 'rb') as f:
while True:
block = f.read(BLOCK_SIZE)
if block:
yield block
else:
return

15.使用enumerate()获取序列的索引和值

def print_index_and_value():
a = ['a','b','c','d']
for i,p in enumerate(a):
print i,p



转载出处:大鱼的鱼塘

待续.......

推荐 3
本文由 GeorgeYao 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

0 个评论

要回复文章请先登录注册