Effective Python(1)

  1. 空白:
  • 使用space来表示缩进,而不要用tab
  • 和语法相关的每一层缩进都要用4个空格来表示
  • 每行的字符数不应超过79
  • 对于占据多行的长表达式来说,除了首行之外的其余各行都应该在通常的缩进级别之上再加4个空格
  • 文件中的函数和类之间应该用两个空行隔开
  • 在同一个类中,各方法之间应该用一个空行隔开
  • 在使用下标来获取列表元素,调用函数或给关键字参数赋值的时候,不要在两旁添加空格
  • 在为变量赋值的时候,赋值符号的左侧和右侧应该各自写上一个空格,而且只写一个就好。
  1. 命令
  • 函数,变量和属性应该用小写字母来拼写,各单词之间以下划线相连,例如:lowercase_underscore
  • 受保护的实例属性,应该以单个下划线开头,例如:_leading_underscore
  • 私有的实例属性,应该以两个下划线开头,例如:__double_leading_underscore
  • 类与异常,应该以每个单词首字母均大写的形式来命令,例如:CapitalizedWord
  • 模块级别的常量,应该全部采用大写字母来拼写,各单词之间以下划线相连,例如:ALL_CAPS
  • 类中的实例方法,应该把首个参数命令为self,以表示该对象自身
  • 类方法的首个参数,应该命令为cls,以表示该类自身
  1. 表达式和语句
  • 采用内联形式的否定词,而不要把否定词放在整个表达式的前面,例如:应该写if a is not b,而不是if not a is b
  • 不要通过检测长度的方法(如if len(somelist) == 0)来判断somelist是否为[]或者""等空值,而是应该采用if not somelist 这种写法来判断,它会假定:空值将自动评估为False
  • 检测somelist是否为[1]或’hi’等非空值时,也应如此,if somelist语句默认会把非空的值判断为True
  • 不要编写单行的if语句,for循环,while循环及except复合语句,而是应该把这些语句分成多行来书写,以示清晰
  • import语句应该总是放在文件开头
  • 引用模块的时候,总是应该使用绝对名称,而不应该根据当前模块的路径来使用相对名称。例如:引入bar包中的foo模块时,应该完整的写出from bar import foo,而不是简写为import foo
  • 如果一定要以相对名称来编写import语句,那就采用明确的写法:from.import foo
  • 文件中的那些import语句按顺序划分为三个部分,分别表示标准库模块,第三方模块以及自用模块。在每一部分中,各import语句应该按模块的字母顺序来排列。
  1. 了解bytes,str
  • bytes是八位二进制数,str是unicode字符,Unicode 转化为bytes使用encode,bytes转化为unicode使用decode。
  • 操作文件对象时,默认以utf-8格式操作,所以传入的参数必须时str,可以使用‘wb’二进制写入模式,’rb‘模式读取文件。
  • str和bytes不能使用>或+一起混合操作。
  1. 用辅助函数来取代复杂的表达式
  • 例如我们想取得url中的信息:
from urllib.parse import parse_qs

my_values = parse_qs('red=5&blue=0&green=',keep_blank_values=True)
#将url中的中文解码成字典
print(repr(my_values))
my_values.get()

这样确实可以取到,但是我们如果想要参数没有值的时候返回0的话,我们可以这样写:

red = my_values.get('red',default=[""])[0] or 0

如果我们想要用到计算:

red = int(my_values.get('red',default=[""])[0] or 0)

这样代码看起来会很冗长,我们应该改写:

red = my_values.get('red',[''])
red = int(red) if red[0] else 0

如果用的频繁,我们可以封装成函数:

def get_first_int(values, key, default = 0):
    found = values.get(key, [''])
    if found[0]:
        found = int(found[0])
    else:
        found = default
    return found

表达式如果变得比较复杂,那就考虑将其拆解成小块,并把这些逻辑移入辅助函数中。

  1. 了解切割序列的方法
  • 切割列表时,即便start和end越界也不会出现问题。利用这一特性,我们可以限定输入序列的最大长度
  • 反之,访问列表的某个元素时,索引不能越界,否则会导致异常。
  • 对原列表进行切割时,会产生另外一份全新的列表。不会影响到原列表。
  • 可以对切片赋值,会把原列表中处在相关范围内的值换成新值,即便长度不同。
  1. 在单次切片操作时,不要同时指定start,end和stride
  • Python中可以将以字节形式存储的字符串反转过来,即指定stride为-1
x = b'wodasdf'
y = x[::-1]
print(y)

这种技巧对字节串和ASCII字符有用,而对于utf-8的unicode字符没有用。

  • 当stride为负值时,表示从末尾向前取值。
  • 当三个值都指定时,会使代码难以阅读,尤其当stride为负值时,所以尽量使用步进式切割,但是这样会多产生一份拷贝,或者考虑内置itertools模块中的islice。
  1. 使用列表推导来取代map和filter
  2. 不要使用含有两个以上表达式的列表推导
  • 如果需要使用,可以使用多个for循环。
  • 列表推导也支持多个if条件,可以使用and连接,也可以使用多个if。
    以下两个表达式等效
x = [x**2 for x in lists if x % 2 == 0 and x % 3 == 0]
x = [x**2 for x in lists if x % 2 == 0 if x % 3 == 0]

  • 每个for循环也可以使用if条件
  1. 用生成器表达式来改写数据量较大的列表推导
  • 列表推导输入数据较多时,如文件等操作,可能会消耗大量内存
  • 生成器表达式是对列表推导和生成器的一种泛化。生成器表达式在运行的时候,并不会把整个输出序列都呈现出来,而是估值为迭代器,这个迭代器每次可以根据生成器表达式产生一项数据
  • 把实现列表推导所用的那种写法放在一对圆括号里,就构成了生成器表达式。使用next每次返回下一个值。
  • 迭代器可以用于另一个生成器表达式。
  1. 尽量用enumerate取代range
  • 在一系列整数上面迭代时,内置的range函数很有用
from random import randint

random_bits = 0
for i in range(64):
    if randint(0,1):
        random_bits |= 1 << i       #a |= b 相当于 a = a|b 按位或  <<左移
        print(random_bits)
  • 但是如果要同时获得列表的索引时,range有一点点麻烦,可以使用enumerate。
a = [0,1,2,3,4,5,6]
for x,a in enumerate(a):
    print(x,a)

第一个为索引,第二个为列表值,同时还可以指定开始计数时所用的值:

a = [0,1,2,3,4,5,6]
for x,a in enumerate(a,1):
    print(x,a)
1 0
2 1
3 2
4 3
5 4
6 5
7 6
  1. 用zip函数同时遍历两个迭代器
  • 对于两个处于相同索引的值有关系时,可以使用其中一个列表的长度来执行,但是不易阅读。即便使用enumerate也比较繁琐
  • zip函数可以平行处理多个迭代器,然后将值汇聚成元组返回。
names = [1,2,3]
letters = [2,3,4]
for name, count in zip(names, letters):
    print(name, count) 
  • 但是如果输入的迭代器长度不同,只要有一个耗尽,zip就提前停止。
  1. 不要在for和while循环中后面写else块
  • if/else中,如果不执行前面那个if块,那就执行else块。
  • try/except中,如果前面try块没有成功执行,那就执行except块。
  • try/except/else中,如果前面try没有失败,则执行else块。
  • try/finally中,无论try成没成功,总是执行finally
  • for/else中,如果循环完整执行,则执行else,如果用break跳出,则不执行else。
  1. 合理利用try/except/else/finally结构中的每个代码块
  • 无论try块是否异常,都可利用try/finally复合语句中的finally块来执行清理工作(如文件的关闭)
  • else 块可以用来缩减try块中的代码量,并把没有发生异常时所要执行的语句与try/except代码块隔开
  • 顺利运行try块后,若想使某些能在finally块的清理代码之前执行,则可将这些操作写到else中。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值