本系列为《编写高质量代码-改善Python程序的91个建议》的读书笔记。
温馨提醒:在阅读本书之前,强烈建议先仔细阅读:PEP规范,增强代码的可阅读性,配合优雅的pycharm编辑器(开启pep8检查)写出规范代码,是Python入门的第一步。
建议36:掌握字符串的基本用法
Python小技巧:Python遇到未闭合的小括号会自动将多行代码拼接为一行和把相邻的两个字符串字面量拼接在一起的。
1 | st = ('select * ' |
- 字符串用法举例:
1 | print isinstance('hello world', basestring) # basestring是str与unicode的基类 |
split()的陷阱示例
1 | ' Hello World'.split(' ') |
title()应用示例
1 | import string |
建议37:按需选择sort()或者sorted()
sorted(iterable[, cmp[, key[, reverse]]]):作用于任何可迭代对象,返回一个排序后的列表;
sort(cmp[, key[, reverse]]]):一般作用于列表,直接修改原有列表,返回为None。
1)对字典进行排序
1 | from operator import itemgetter |
2)多维list排序
1
2
3
4
5
6
7from operator import itemgetter
game_result = [['Linda', 95, 'B'], ['Bob', 93, 'A'], ['Carol', 69, 'D'], ['zhangs', 95, 'A']]
sorted_res = sorted(game_result, key=itemgetter(1, 2)) # 按照学生成绩排序,成绩相同的按照等级排序
print game_result
[['Linda', 95, 'B'], ['Bob', 93, 'A'], ['Carol', 69, 'D'], ['zhangs', 95, 'A']]
print sorted_res
[['Carol', 69, 'D'], ['Bob', 93, 'A'], ['zhangs', 95, 'A'], ['Linda', 95, 'B']]
3)字典中混合list排序
1 | from operator import itemgetter |
4)list中混合字典排序
1 | from operator import itemgetter |
建议38:使用copy模块深拷贝对象
浅拷贝(shallow copy):构造一个新的复合对象并将从原对象中发现的引用插入该对象中。实现方式有:工厂函数,切片操作,copy模块中copy操作等;深拷贝(deep copy):构造一个新的复合对象,但是遇到引用会继续递归拷贝其所指向的具体内容,也就是说它会针对引用所指向的对象继续进行拷贝,因此产生的对象不受其他引用对象操作的影响。实现方式有copy模块中的deepcopy()操作。实例
1 | #!/usr/bin/env python |
- 运行结果如下:
1 | ==============Customer one order info================= |
建议39:使用Counter进行计数统计
- 使用
dict
1 | some_data = ['a', 2, '2', 4, 5, '2', 'b', 7, 'a', 5, 'd', 'a', 'z'] |
- 使用
defaultdict
1 | from collections import defaultdict |
- 使用
set与list
1 | some_data = ['a', 2, '2', 4, 5, '2', 'b', 7, 'a', 5, 'd', 'a', 'z'] |
- 使用更为优雅的
Pythonic方法—collections.Counter
1 | from collections import Counter |
建议40:深入理解ConfigParser
- 实例
1 | #!/usr/bin/env python |
建议41:使用argparese处理命令行参数
1 | import argparse |
建议42:使用pandas处理大型csv文件
csv作为一种逗号分隔型值的纯文本格式文件,常见于数据库数据的导入导出、数据分析中记录的存储等。
以下列举几个与csv处理相关的API:
csv.reader(csvfile[, dialect='excel'][, fmtparam]):用于CSV文件的读取,返回一个reader对象用于在CSV文件中进行行迭代;csv.writer(csvfile, dialect='excel', **fmtparams):用于写入CSV文件;csv.DictReader(csvfile, fieldnames=None, restKey='', restval='', dialect='excel', *args, **kwds):用于支持字典的读取;csv.DictReader(csvfile, fieldnames=None, restval='', extrasaction='raise', dialect='excel', *args, **kwds):用于支持字典的写入。实例
1 | import csv |
csv使用非常简单,基本可以满足大部分需求,但是对于上百MB或G级别以上的文件处理无能为力。这种情况下,可以考虑使用pandas模块,它支持以下两种数据结构。
Series:是一种类似数组的带索引的一维数据结构,支持的类型与NumPy兼容。
1 | from pandas import Series |
DataFrame:类似于电子表格,其数据为排好序的数据列的集合,每一列都可以是不同的数据类型,类似一个二维数组,支持行和列的索引。
1 | from pandas import DataFrame |
pandas中处理CSV文件的函数主要为read_csv()和to_csv()。
- 指定读取部分列和文件的行数
1 | import pandas as pd |
- 设置
CSV文件与excel兼容
1 | import csv |
- 对文件进行分块处理并返回一个可迭代的对象
1 | reader = pd.read_table('/home/projects/pythoner/quality_code/csv_test.csv', chunksize=5, iterator=True) |
- 当文件格式相似时,支持多个文件合并处理
1 | file_list = ['/home/projects/pythoner/quality_code/csv_test1.csv', '/home/projects/pythoner/quality_code/csv_test2.csv'] |
建议43:一般情况使用ElementTree解析XML
ElementTree解析XML具有以下特性:
- 使用简单,将整个
XML文件以树的形式展示,每一个元素的属性以字典的形式表示,非常方便处理; - 内存上消耗明显低于
DOM解析; - 支持
XPath查询,非常方便获取任意结点的值。
建议44:理解模块pickle优劣
1)pickle.dump(obj,file[,protocol]):序列化数据到一个文件描述符。 其中:protocol为序列化使用的协议版本,0表示ASCII协议,为默认值;1表示老式的二进制协议;2表示2.3版本引入的新二进制协议。
2)pickle.load():表示把文件中的对象恢复为原来的对象,这个过程也被称为反序列化。
1 | import cPickle as pickle |
pickle的优点:
1)接口简单,容易使用;
2)pickle的存储格式具有通用性,能够被不同平台的Python解析器共享;
3)支持的数据类型广泛;
4)pickle模块是可扩展的;
5)能够自动维护对象间的引用。
pickle的缺点:
1)
pickle不能保证操作的原子性;
2)pickle存在安全性问题;
3)pickle协议是Python特定的,不同语言之间的兼容性难以保证。
建议45:序列化的另一个不错的选择—JSON
JSON具有以下优势:
- 使用简单,支持多种数据类型;仅存在两大数据结构:名称/值对的集合(对象,记录,结构,字典,散列表,键列表,关联数组等);值的有序列表(数组,向量,列表,序列等)。
- 存储格式可读性好,容易修改;
json支持跨平台跨语言操作,能够轻易被其他语言解析,存储格式较紧凑,所占空间较小;- 具有较强的扩展性;
json在序列化datetime时会抛出TypeError异常,需要对json本身的JSONEncoder进行扩展。
建议46:使用traceback获取栈信息
- 实例
1 | import trackback |
输出结果如下:
1 | Error: list index out of range |
建议47:使用logging记录日志信息
1,日志级别
| Level | 使用情形 |
|---|---|
| DEBUG | 详细的信息,在追踪问题时使用 |
| INFO | 正常的信息 |
| WARNING | 一些不可预见的问题发生,或者将要发生,如磁盘空间低等,但不影响程序的运行 |
| ERROR | 由于某些严重的问题,程序中的一些功能受到影响 |
| CRITICAL | 严重的错误,或者程序本身不能继续运行 |
2, logging lib的四个主要对象
logger:程序信息输出的接口,分散在不同的代码中,使得程序可以在运行时记录相应的信息,并根据设置的日志级别或者filter来决定哪些信息需要输出,并将这些信息分发到其关联的handler。Handler:用来处理信息的输出,可以将信息输出到控制台、文件或者网络。Formatter:决定log信息的格式。Filter:决定哪些信息需要输出,可以被handler和logger使用,支持层次关系。
logging.basicConfig([**kwargs]) 提供对日志系统的基本配置,默认使用StreamHandler和Formatter并添加到root logger。字典参数列表如下:
| 格式 | 描述 |
|---|---|
| filename | 指定FileHandler的文件名,而不是默认的StreamHandler |
| filemode | 打开文件的模式,默认为‘a’ |
| format | 输出格式字符串 |
| datefmt | 日期格式 |
| level | 设置root logger的日志级别 |
| stream | 指定StreamHandler,若与filename冲突,忽略stream |
- 实例
1 | def get_logger(file_name, level=logging.INFO): |
3,使用建议
1)尽量为
logging取一个名字而不是采用默认,eg:logger=logging.getLogger(__name__);
2)为了方便找出问题,logging的名字建议以模块或者class命名;
3)logging只是线程安全的,不支持多进程写入同一个日志文件。
建议48:使用threading模块编写多线程程序
Python多线程支持两种方式创建:
1)通过继承
Thread类,重写其run()方法(不是start()方法);不支持守护线程;
2)创建threading.Thread对象,在它的初始化函数(__init__())中将可调用对象作为参数传入。
建议49:使用Queue使多线程编程更加安全
Python中的Queue模块提供了以下队列:
Queue.Queue(maxsize):先进先出,maxsize为队列大小,其值为非正数时为无限循环队列;Queue.LifoQueue(maxsize):后进先出,相当于栈;Queue.PriorityQueue(maxsize):优先级队列。生产-消费者模式实现
demo:
1 | #!/usr/bin/env python |