Effective Python note(1)
Effective Python note(1)
Pythonic:
PEP8 的一些重要规范:
- 每行字符数不超过79
- 长表达式换行时,首行后每行额外缩进4个空格
- 文件中函数与类间用两个空行分隔
- 同一类内各方法间用一个空行隔开
- 函数、变量及属性命名使用小写字母并以下划线相连,如
lowercase_underscore
- 受保护实例属性以单下划线开头,例如
_leading_underscore
- 私有实例属性以双下划线开头,例如
__double_leading_underscore
- 类与异常名采用每个单词首字母大写的格式,例如
CapitalizedWord
- 模块级别常量全用大写字母拼写,单词间以下划线连接,如
ALL_CAPS
- 类方法首个参数应命名为
cls
表示该类自身 - 如必须相对导入,则明确书写:
from . import foo
- 文件中的import语句按顺序分为三部分:标准库模块、第三方模块和自定义模块。各部分内部按照模块名称字母顺序排列import语句
- 检查
somelist
是否为非空值(如[1]或’hi’)时,遵循此原则;非空值在条件判断中默认视为True - 用
zip
函数同时遍历两个迭代器
bytes 和 str区别与操作
- 类型本质:
str
(字符串):表示文本数据,存储的是Unicode编码的字符序列。Python 3中所有文本字符串默认都是Unicode编码的bytes
(字节串):表示二进制数据,存储的是一个8位字节的序列。它通常用于网络传输、磁盘文件读写等场景,可能包含图像、音频等原始非文本数据
- 内容形式:
str
类型的数据由一系列Unicode码点组成,每个码点对应一个字符bytes
类型的数据是由一连串的整数(0-255)组成的序列,这些整数代表了原始字节值
- 操作方式:
str
字符串可以进行各种文本操作,如连接、查找、替换等,并支持多语言字符bytes
字节串不能直接进行文本处理操作,但可以执行二进制操作,如按字节切片、比较等
- 转换关系:
- 从文本到二进制:通过编码(encoding),将
str
转换为bytes
,例如使用my_str.encode('utf-8')
将文本转换成UTF-8编码的字节串 - 从二进制到文本:通过解码(decoding),将
bytes
转换为str
,例如使用my_bytes.decode('utf-8')
将UTF-8编码的字节串转换回文本
- 从文本到二进制:通过编码(encoding),将
Python 3 不允许隐式地混合 str
和 bytes
数据,比如你不能拼接字符串和字节流,也不能在字节串里搜索字符串,必须显式地进行类型转换后才能进行相应的操作。编写Python程序时,一定要先把编码和解码操作放在界面外围,程序的核心部分使用str
数据类型,且不要对编码做任何假设
例如我们需要编写接受str
或bytes
,并总是返回str
的 方法
1 |
|
合理利用try except else finally
结构中的每个代码块
-
try 块用于测试一段代码是否存在错误
-
except 块用于处理错误
-
else 块用于在没有错误时执行代码
-
finally 块用于无论 try 和 except 块的结果如何都要执行的代码
不论try
块是否发生异常,均可通过try/finally
复合语句中的finally
块执行清理工作。若在成功执行try
块后,希望在finally
块的清理代码之前执行某些操作,则可将这些操作置于else
块中
1 |
|
函数:
- 尽量使用异常来表示特殊情况,而不是返回None
- 慎用
nonlocal
语句,因为它像global
那样容易被滥用。建议仅在非常简单的函数中使用这种机制。nonlocal
的副作用很难追踪 - 考虑使用生成器来改写直接返回列表的函数
- 使用只能以关键字形式指定的参数,以确保代码明晰
*args
与**kargs
参数使用:
- 令函数接受可选的位置参数(由于这种参数习惯上写作
*args
,所以又被称为star args
或星号参数),能够使代码更加清晰,并减少 visual noise - 尽量只在函数参数个数少的情况下使用这两个可变长参数
- 在已经接受
*args
参数的函数上面继续添加位置参数,可能会产生难以排查的bug
例如,要定义一个log
函数以便打印一些调试信息:
1 |
|
在这个例子中,log
函数通过*values
参数可以接受任意数量的额外参数,这些参数在打印时会被格式化为一个列表。这种使用*args
的方式使得函数调用更加灵活,同时也提高了代码的可读性
但是这种参数会带来两个问题:
- 变长参数在传给函数时,总是要先转化成元组(tuple)。这意味着,如果用带有 * 操作符的生成器作为参数来调用这种函数,那么 Python 就必须要先把该生成器完整地迭代一轮,并将生成器所生成的每一个值都存储起来。这可能会消耗大量内存,并导致程序崩溃
- 如果以后要给函数添加新的可选位置参数,那就必须修改原来调用该函数的那些旧代码。若是只给参数列表前方添加新的可选位置参数,而不更新现有的调用代码,那么可能会产生难以调试的错误
对于第二个问题,我们可以使用**kargs
参数或者*
符号解决:
在Python3中,定义的参数之间加上*
,它表示在该位置之前的所有参数必须是位置参数,而*
之后的所有参数必须是关键字参数。
1 |
|