【Effective Python】读书笔记-01培养Pythonic思维

1. 遵循 PEP 8 风格指南

https://www.python.org/dev/peps/pep-0008

关于空白

用空格(space)表示缩进,而不要用制表符(tab)。
和语法相关的每一层缩进都用 4 个空格表示。
每行不超过 79 个字符。
对于占据多行的长表达式来说,除了首行之外的其余各行都应该在通常的缩进级别之上再加 4 个空格。
在同一份文件中,函数与类之间用两个空行隔开。
在同一个类中,方法与方法之间用一个空行隔开。
使用字典时,键与冒号之间不加空格,写在同一行的冒号和值之间应该加一个空格。
给变量赋值时,赋值符号的左边和右边各加一个空格,并且只加一个空格就好。
给变量的类型做注解(annotation)时,不要把变量名和冒号隔开,但在类型信息前应该有一个空格。

命名

函数、变量、属性:lowercase_underscore
受保护的实例属性:_leading_underscore
私有的实例属性:**double_leading_underscore
类和异常:如:**double_leading_un
模块级别的常量:ALL_CAPS
类中的实例方法:应该把第一个参数命名为 self,用来表示该对象本身。
类方法的第一个参数:cls,表示类的本身

规范表达式和语句的写法

  • 采用行内否定,把否定词直接写在否定内容的前面 if not a is b -> if a is not b
  • 不要通过长度判断容器或序列是不是空的。Python 会自动把空值评定为False
  • 不用通过长度来判断容器或序列中有没有内容。python 会自动把非空的值判断为True
  • if 语句、for 循环、while 循环及 except 复合语句,应该分成多行来写
  • 多行的表达式,应该用括号括起来,而不要用\符号续行

引入 import

  • import 语句总是放在最开头,应该使用决定名称。总是应该使用绝对名称,而不应该根据当前模块路径来使用相对名称。例如,要引入 bar 包中的 foo 模块,应该完整地写出 from bar import foo,即便当前路径为 bar 包里,也不应该简写为 import foo。
  • 如果一定要用相对名称来编写 import 语句,那就应该明确地写成:from . import foo。
  • 分成三部分:
    1. 标准库模块
    2. 第三方模块
    3. 自己的模块
  • 同一部分的 import 语句按照字母顺序排列。

2. bytes 和 str 的区块

表示字符序列的两种类型:

  • bytes:8 位无符号值
  • str:Unicode 码点(code point)

Unicode 转二进制:str.encode
二进制数据转 Unicode 数据:bytes.decode

Unicode 三明治:编码和解码操作放在最外层,程序的核心部分可以使用 unicode 数据来运作(str 类型表示 unicode1 数据)。

辅助函数 1:bytes 转 str

def to_str(bytes_or_str:bytes) -> str:
    if isinstance(bytes_or_str, str):
        return bytes_or_str
    else:
        return bytes_or_str.decode()

辅助函数 2:str 转 bytes

def to_bytes(bytes_or_str: str) -> bytes:
    if isinstance(bytes_or_str,bytes):
        return bytes_or_str
    else:
        return bytes_or_str.encode()

bytes 类型、str 类型都可以使用+运算符和进行比较,但是 bytes 和 str 之间不行,若比较 bytes 和 str 实例,始终返回False

with open() as f的句柄默认需要使用 unicode 字符串操作,而不能采用原始的 bytes。

要注意当前操作系统的默认编码标准,获取该标准的方法:

python -c 'import locale; print(locale.getpreferredencoding())'

3. 用支持插值的 f-string 取代 C 风格的格式字符串与 str.format 方法

Python 3.6 添加了一种新的特性,叫作插值格式字符串(interpolated format string,简称 f-string)。

语法特性要求:在格式字符串前面加字母 f 作为前缀。

  • 可以直接在 f-string 的{}里面引用当前 Python 范围内的所有名称
  • 通过!符号把值转换成 Unicode 及 repr 形式的字符串
  • 在{}内的冒号右侧支持str.foramte方法所支持的迷你语言。
name = 'zhanghaohan'
value = 1.3256
places = 3

# name: zhanghaohan
print(f'name:{name}')
# 解决小数点之后位数的硬编码问题 1.33
print(f'{value:.{places}}')
# 清楚地表达逻辑 value:1
print(f'value:{round(value)}')

4. 用辅助函数取代复杂的表达式

语法简洁的 Python 虽然可以写出很多浓缩的句式,但应该避免让这样的写法把表达式弄得太复杂。我们要遵循 DRY 原则,也就是不要重复自己写过的代码(Don’t Repeat Yourself)。

复杂的表达式,尤其是需要重复使用的表达式,应该写到辅助函数里。

if/else 结构写成的表达式比用 or、and 写成的 Boolean 表达式更好懂。

5. 把数据结构直接拆分到多个变量里,不要专门通过下标访问

拆分(unpacking)可以把元组里面的元素分别赋给多个变量,这些变量可以修改。该方法比直接通过下标去访问元组内的元素更加清晰,需要的代码更少。

一行代码交换元素的原因:创建临时元组

a = 1
b = 2
a, b = b, a

unpacking 机制的另一个用法:在 for 循环或类似结构中,把复杂的数据拆分到相关的变量中。

temp = {
    '1': ('a', 'b'),
    '2': ('a', 'b'),
}

for key, (a, b) in temp.items():
    print(key, a, b)

6. 尽量使用 enumerate 取代 range

内置函数 enumerate:

  • 能够把任何一种迭代器(iterator)封装成惰性生成器(lazy generator)
  • 每次循环只需要从 iterator 取出下一个值,并且给出本轮编号
  • enumerate 接受第二个参数,指定开始的序号

案例:

my_son_list = [
    'zhangchi',
    'zhangshuai',
    'zhangsan'
]

for index, son in enumerate(my_son_list):
    print(index, son)

输出:

0 zhangchi
1 zhangshuai
2 zhangsan

有啥好处?

7. 用 zip 函数同时遍历两个迭代器

场景:需要同时遍历两份列表。

Python 内置的 zip 函数:

  • 能把两个或更多的 iterator 封装成惰性生成器(lazy generator)
  • 每次只从它封装的那些迭代器里面各自取一个元素,减少内存的占用。
  • 只要任何一个迭代器处理完毕,就不会再往下走。(如果无法确定长度是否相等,应该使用itertools.zip_longest函数

用法:

names = [
    'zhangsan', 'lisi', 'wangwu'
]
ages = [
    18, 19, 20
]

for name, age in zip(names, ages):
    print(name, age)

输出:

zhangsan 18
lisi 19
wangwu 20

8. 不要在 for 和 while 循环后面写 else 块

Python支持一个大多数语言都不支持的特性,即把 else 紧跟在整个循环的后面。

for-else

  • 如果循环没有从头到尾执行完,那么 else 块的代码不会执行
  • 对空白序列做 for 循环,那么程序立刻就会执行 else 块。

while

  • 如果循环没有从头到尾执行完,那么 else 块的代码不会执行
  • 如果首次循环就遇到 False,那么程序也会立刻运行 else 块。

else 使用的场景:实现搜索逻辑,如判断两个数是否互质。

不建议在 for 和 while 后面使用 else 块,可以用如下两个方案替代

  1. 只要发现某个条件成立,就立刻返回,如果始终都没碰到这种情况,那么循环就会完整地执行,让程序返回函数末尾的那个值作为默认返回值。

  2. 用变量来记录循环过程中有没有碰到这样的情况,如果有,那就用 break 提前跳出循环,如果没有,循环就会完整地执行,无论如何,最后都返回这个变量的值。

9. 用赋值表达式减少重复代码

a = b 是 a equals b
a := b 是 a walrus b

场景:只有 if-else 结构需要使用的变量

import random


def get_data():
    return random.randrange(0, 100)


if (a := get_data()) > 10:
    print(f'{a} > 10')
elif a < 10:
    print(f'{a} < 10')

你可能感兴趣的:(python,java,mysql)