改善Python程序的建议

三元操做符:
咱们都知道在C语言中,三元操做符为C ? X : Y,在人们的强烈要求下,python2.5以后三元操做符等价为X if C else Ypython

何时应该使用断言?
断言的基本语法以下:
assert expression1 ["," expression2]
计算expression1的值会返回True或者False,当值为False的时候会引起AssertError,而expression2是可选的,经常使用来查看具体的异常信息。
断言是有代价的,会对性能产生必定的影响,但python并无严格定义调试与发布模式之间的差异,一般禁用断言的方法是在运行脚本时加上-O标志,这种方法带来的影响是它不优化字节码,而是忽略与断言有关的语句。
断言是用来捕获用户定义的约束的,不是用来捕获程序自己的错误的。express

  • 断言应该被使用在正常逻辑不可到达的地方或正常状况下老是为真的场合。app

  • 异常能处理就不要使用断言。函数

  • 不要用断言检查用户输入。性能

  • 当函数调用后,须要肯定返回值是否合理时可使用断言。优化

  • 当条件是业务逻辑继续的先决条件时可使用断言。调试

我最近在一个爬虫代码里使用了几回断言,使用断言是为了保证程序自身所记录的页数与爬虫所运行到的页数相同,不然会在存储数据时发生错误。code


数据交换值时不推荐使用中间变量
x,y = y,x 这种方法有更好的性能。 对象

构建合理的包层次来管理module
本质上每个python文件都是一个模块,但在大的项目中把全部的python文件放在一个目录下不是一个好的作法。咱们应该用package包来管理模块。
__init__.py的一些做用:内存

Package/ __init__.py
  Module1.py
  Module2.py
  Subpackage/ __init__.py
        Module1.py
        Module2.py
  • 使包和普通目录区分

  • 若是咱们在Package包下的__init__.py中添加:
    from Module1 import Test语句,则能够直接使用from Package import Test来导入类Test

  • __init__.py为空,意图使用from Package import *语句将包Package中全部的模块导入当前命名空间将会失败。它仅仅会执行__init__.py文件。所以咱们须要修改__init__.py文件。
    若是咱们在__init__.py文件中添加:

__all__ = ['Module1','Module2','Subpackage']
这样咱们就能使用from Package import *语句将包Package中全部的模块导入当前命名空间。


使用with自动关闭资源
with语句能够在代码块执行完毕后还原进入该代码块时的现场。在文件管理时使用with总能保证文件被正常关闭。

None的特殊性
全部被赋值为None的变量相等,而且None与任何其余非None的对象比较结果都为False.

字符串的链接特别是大规模字符串的处理,应该优先使用join而不是+。
若是咱们进行如下操做:S1+S2+S3+..,执行一次+操做便会在内存中申请一块新的内存,并将上一次操做的结果和本次操做的右操做数复制到该内存中。在N个字符串链接中,会产生N-1个中间结果,每产生一个中间结果都要申请和复制一次内存,总共要申请N-1次内存,严重影响效率。时间复杂度接近O(n^2)。
而当使用join()方法链接字符串时,会首先计算须要申请的总的内存空间,而后一次性申请所需内存并将字符序列中的每个元素复制到内存中。时间复杂度为O(n)。

python中一切皆对象,每个对象都有一个惟一的id。
函数传参既不是传值也不是传引用
在C/C++中,若是执行:

a = 5;
b = a;
b = 7;

在内存中申请一块内存并将a的值复制到该内存中,当执行b = 7时将b对应的值从5改到7。
而对于python,赋值并非复制,b=a使得a和b引用同一个对象。b=7则是将b指向对象7。
python函数参数究竟是传值仍是传引用,实际都不是,而是传对象或者说传对象的引用。
对可变对象的修改在函数外部以及内部均可见,调用者和被调用者之间共享这个对象。
对于不可变对象,因为并不能真正修改,由于,修改每每是经过生成一个新对象而后赋值来实现的。

警戒默认参数潜在的问题

def在python中是一个可执行的语句,当解释器执行def时,默认参数也会被计算,并存在函数的.func_defaults属性中。  
因为Python中函数参数传递的是对象,可变对象在调用者和被调用者之间共享。
def appendtest(newitem,lista=[]):
    print(id(lista))
    lista.append(newitem)
    print(id(lista))
    return lista

>>> appendtest(1)
12345
12345
[1]
>>> appendtest('a')
12345
12345
[1,'a']

PS:咱们能够用这个属性,统计某个方法被调用的次数。
若是不想让默认参数所指向的对象在全部的函数调用中共享,而是在函数调用的过程当中动态生成,可在定义的时候使用None对象做为占位符。

def appendtest(newitem,lista=None):
    print(id(lista))
    lista.append(newitem)
    print(id(lista))
    return lista

str()和repr()的区别:目标不一样:str()面向用户,repr()面向解释器和开发人员
字符串的一些技巧:

  • python遇到未闭合的小括号时会自动将多行代码拼接为一行和把相邻的两个字符串字面量拼接在一块儿。

s = ('SELECT * '
    'FROM atable '
    'WHERE afirld="value"')
print(s)
>>> SELECT * FROM atable WHERE afirld="value"
  • str的一些方法
    str方法不少,只说几个有意思的:

count()能查找子串在字符串中出现的次数,这个方法在调用replace方法时能使用,能够批量替换。
replace(old,new[,count])用以替换字符串的某些子串,若是指定count参数,就最多替换count次,不指定则替换所有。


参考资料:《编写高质量代码:改善Python程序的91个建议》

相关文章
相关标签/搜索