编写高质量代码:改善Python程序的91个建议.1

人生苦短,睡觉最好!

-U 是--upgrade的缩写,如果以已经安装就升级到最新版

先得安装一下

输出的没毛病

我们实验一下

我提前把代码改过

pep8 --show-source --show-pep8 .\search2.py
--show-source --show-pep8

一个是显示哪里不符合

一个是显示正确的写法

笔记

Python的库

sphinx,生成文档注释

注释

就是先写注释,再写逻辑.对于不用的代码要不要保留的.注意空行的使用,保持上下文语言的理解性,调用者在上,被调用者在下

def A():
B()
def B():
pass

避免过长的代码行,最好不要超过80个字符.逗号和分号前不要使用空格

函数的设计原则

1.函数的设计要短小,嵌套的层次不宜过深(控制在三层以内)
2.函数的声明应该做到合理,简单,易于使用
3.函数参数参数设计应该考虑向下兼容
4.一个函数只能做一件事,尽量保证函数语句粒度的一致性. \

函数的向下兼容

通过加入默认参数来避免这种退化,做到向下兼容,不要在函数中定义可变对象作为默认值,使用异常替换返回错误,保证通过单元测试

常量

Python内部没有常量的功能.通过命名风格标识,通过定义的类来实现

import sys
class _const:
class ConstError(TypeError):
pass

class ConstCaseError(ConstError):
pass

def __setattr__(self, name, value):
if self.__dict__.has_key(name):
raise self.ConstError, "Can't change const.%s" % name
if not name.issuper():
raise self.ConstError, 'const name'"%s" is not all uppercas'% name
self.__dict__[name] = value

sys.modules[__name__] = _const()

以上代码就完成了,使用的时候:

import const
const.COMPANY = "IBM"

这样处理过后,代码一旦赋值就不会被更改.最好集中在一起统一管理

import const
import sys

class _const:
class ConstError(TypeError):
pass

class ConstCaseError(ConstError):
pass

def __setattr__(self, name, value):
if self.__dict__.has_key(name):
raise self.ConstError, "Can't change const.%s" % name
if not name.issuper():
raise self.ConstError, 'const name'"%s" is not all uppercas'% name
self.__dict__[name] = value

sys.modules[__name__] = _const()
const.MY_CONST = 1
const.MY_SCOND_CONST = 2
const.MY_THIRD_CONST*2

最后的文件就是这样的

from constant import const
print(const.MY_SCOND_CONST)
print(const.MY_THIRD_CONST)

调用的时候就是这样的写法

assert(断言)语句

x = 1
y = 2
assert x == y,"not equals"

我们先写一个,看看是什么样的

AssertionError Traceback (most recent call last)
<ipython-input-1-12234b9328bc> in <module>
1 x = 1
2 y = 2
----> 3 assert x == y,"not equals"

AssertionError: not equals

以上为打印的结果

x = 1
y = 2
# assert x == y,"not equals"
if __debug__ and not x==y:
raise AssertionError("not equals")

其实等价的语句为这样

AssertionError Traceback (most recent call last)
<ipython-input-2-a11717d6503d> in <module>
3 # assert x == y,"not equals"
4 if __debug__ and not x==y:
----> 5 raise AssertionError("not equals")

AssertionError: not equals

这个是等价的输出.

需要知道一点,断言是影响性能的,需要在后面加上**-O**这样的执行开关

python -O filename.py

这样就可以了.

以及注意,如果本身的异常可以处理就不要用断言了,不要用断言来检查用户的输入,应该使用条件判断,不符合的时候打印一些错误提示.当函数有返回值的时候可以使用断言.判断业务逻辑的时候可以使用断言

数据交换

x,y = y,x

直接这样写就好了.那里面是什么样的原理呢?
x,y = y,x的实现机制--元组
假如x=2,y=3。运行时,首先构造一个元组(y,x),然后构造另一个元组(x,y),接着用元组(y,x)赋值给(x,y),元组赋值过程从左到右,依次进行。根据元组的特性,此时构造的元组的两个元素并不是x和y,而是这两个变量所指向的地址空间里的内容。如果此时再另x=y,即x=3,在地址空间中会另开辟出一块空间存储3,x进而指向这块空间,而元组中的值仍然保持不变,即元组中的x仍然等于2。因此,再实现y=x的赋值时,y的值为2,从而实现交换变量的值。

简单来说,对于“x,y=y,x”,有y,x所构成的元组(y,x)其实应该表示为(3,2),然后进行赋值就可以交换变量的值了。
import dis
def swep1():
x=2
y=3
x, y = y, x

def swep2():
x =2
y =3
temp = x
x = y
y = temp

# print('swep1()')
# swep1()
dis.dis(swep1)
dis.dis(swep2)

此为用字节码分析的源码

3 0 LOAD_CONST 1 (2)
2 STORE_FAST 0 (x)

4 4 LOAD_CONST 2 (3)
6 STORE_FAST 1 (y)

5 8 LOAD_FAST 1 (y)
10 LOAD_FAST 0 (x)
12 ROT_TWO
14 STORE_FAST 0 (x)
16 STORE_FAST 1 (y)
18 LOAD_CONST 0 (None)
20 RETURN_VALUE
8 0 LOAD_CONST 1 (2)
2 STORE_FAST 0 (x)

9 4 LOAD_CONST 2 (3)
6 STORE_FAST 1 (y)

10 8 LOAD_FAST 0 (x)
10 STORE_FAST 2 (temp)

11 12 LOAD_FAST 1 (y)
14 STORE_FAST 0 (x)

12 16 LOAD_FAST 2 (temp)
18 STORE_FAST 1 (y)
20 LOAD_CONST 0 (None)
22 RETURN_VALUE

执行结果,第二段代码生成了三个load_fast和三store_fast的指令,而rot_two是交换两个栈的最顶层元素,它比执行一个load_fast+store_fast快

惰性运算

Lazy evaluation常被译为“延迟计算”或“惰性计算”,指的是仅仅在真正需要执行的时候才计算表达式的值。人的自然性情,在多的情况下,倾向于快。计算机性能优越的情况下,程序员倾向快速编写出可运行的代码,质量的问题会凸显。延迟计算这样的方法,是需要花费心力的,Lazy evaluation 其实并不 lazy .而且资源永远都是有限的,而需求永远都是无法满足的。性能效率是永恒的话题。

短路求值

短路求值。几乎所有语言都有的特性,这说明了这个优化的重要性。但觉得这不是lazy evaluation的重点。lazy evaluation还是一种“能拖就拖,假装自己完成了每项工作流程,但其实只是记到小本本上了,直到老师要求交作业时实在没法拖时才真正开始写”的感觉。但是老师不收作业的时候,它就可以不用写了~lazy的目的是万一最后不需要计算就省资源.因此在编程过程中,如果对于or条件表达式应该将值为真可能性较高的变量写在or的前面,而and则应该推后。

无限的数据结构

生成器可以节省空间,因为它的操作结果是“一个”而不是“一组”。常见的生成器函数包含yield和无限循环,而且会被多次调用,每次调用走到yield语句即返回,下次再被调用则从yield 语句的下一个语句开始执行,直到yield语句返回,循环往复因此可以“无限”. itertools模块包含创建有效迭代器的函数,可以用各种方式对数据进行循环操作,此模块中的所有函数返回的迭代器都可以与for循环语句以及其他包含迭代器(如生成器和生成器表达式)的函数联合使用。
创建一个迭代器,生成项的方式类似于切片返回值:iterable[start : stop : step],将跳过前start个项,迭代在stop所指定的位置停止,step指定用于跳过项的步幅。与切片不同,负值不会用于任何start,stop和step,如果省略了start,迭代将从0开始,如果省略了step,步幅将采用1.

def islice(iterable, *args):
# islice('ABCDEFG', 2) --> A B
# islice('ABCDEFG', 2, 4) --> C D
# islice('ABCDEFG', 2, None) --> C D E F G
# islice('ABCDEFG', 0, None, 2) --> A C E G
s = slice(*args)
it = iter(xrange(s.start or 0, s.stop or sys.maxint, s.step or 1))
nexti = next(it)
for i, element in enumerate(iterable):
if i == nexti:
yield element
nexti = next(it)

#如果start为None,则迭代从零开始。如果step为None,则该步骤默认为1。
#在版本2.5中已更改:默认设置为start和step,不接受None值。

枚举二三事

谈起枚举的话,最经典的就是季节和星期了.,它能够以更接近自然语言的方式来表达数据,可是在Python内没有被加进来,之前也申请过~
1.使用类属性

class Season:
Spring = 0
Summer = 1
Autumn = 2
Winter = 3
print(Season.Spring)

让我们再简化一点,让他看起来更像是一个枚举~

class Season:
Spring,Summer,Autumn,Winter = range(4)

或者...为什么不写一个函数呢?

def enum(*posarg,**kwargs):
return type("Enum",(object,),dictt(zip(posarg,xrange(len(posarg))),**kwargs))
Seasons = enum("Spring", "Summer", "Autumn", "Winter1=1")
Seasons.Spring

不推荐使用type来进行类型检查

(0)

相关推荐