读《Effective Python:编写高质量Python代码的59个有效方法》小记


读《Effective Python:编写高质量Python代码的59个有效方法》小记

写在前面

 Python 很优美的语言,近几年迅速成为最流行的语言,为什么?

  1. 语言的全面性:啥都能干,数学计算,GUI开发,WEB开发(框架近百种),AI分析,数据量化分析、爬虫、文档处理等等;
  2. 易用性: 很多非IT的人群,学习该语言,入门简单,易于使用。毫不夸张的说:有时候,Python的一行代码可以抵得上C语言100行代码,效率上还相近,Why not 不用?

2010年,个人在IT公司,进驻华东某省银行分行进行中间业务平台建设,用的Python2.3 语言开发项目,当时纯粹作为应用,没有深入去思考该脚本语言的起始,如今从Python 3.6+ 入手,无论从风格,还是封装性,全面性都有本质的提升。

 随着年龄增长,Python很显然让我有了抛弃C/C++ 、java语言的想法。尽管google公司依据python,开发了编译型的GO语言,但仅是在某些方面表现卓越,不如Python的通用性。

未来是脚本语言的天下,Python必然是这方面的王者。

# 任何部分的知识点 都应该遵循”WHY、WHAT、HOW、WHERE“去学习。
# WHY:为什么存在,即背景;
# WHAT: 是什么,概念;
# HOW: 怎么使用;
# WHERE: 什么时候使用 或 在哪里需要使用。

Chapter 1: 用Pythonic 方式思考

1. Python式编程风格(Pythonic)

# 选定合适的python版本
# Python是解释型、强类型语言

>>>  python --version
# 或
>>> import sys
>>> print(sys.version_info)
>>> print(sys.version)

# 变量 :驼峰或下划线单词间隔(推荐后一种)
# 常量 :约定俗成 全部大写 代表不修改,实际语言上是可以修改,Python中无C语言中的const 修饰符。 示例:BIRTH_OF_CHINA = 1949
# 注释: 出于阅读理解的需要,注释是个很好的习惯。
# 单行注释:#;多行注释 ‘’‘注释内容’‘’  或 “”“注释的内容 ”“”
”“”
     基础数据类型:是对现实信息的精准划分。数字、汉字、英文……;机器很傻 需要指定类型 告诉计算机 数据的类型。
    整形:1, 10 等 加减乘除
    字符串:单引号 和 双引号 等价;还有三引号  ’‘’  用于换行的字符串
            单引号 和 双引号 可以配合使用。
            示例: age = ” I’am lei.wang “
    布尔类型:True 或 False
    查看变量类型  type(var)
“”“ 

2.遵循PEP8 风格(习惯很重要)

# PEP 全称为:Python Enhancement Proposal #8 
# 即8号python增强提案
# Zen Of Python  
# Python 之禅
# command line mode 模式
>>> import this 

3. Python3与Python2的区别

  1. python3:bytes 表示二进制 ,str 表示unicode;
  2. python2:str表示二进制 ,unicode表示unicode;
  3. 转换utftobin 用encode(),解码用decode();
  4. 文件操作上 python3用utf8方式,所以在对二进制操作时候,要rb或wb模式;python2中默认用二进制操作文件,兼容上述表达。

4. 切片

  1. 在Python中,空字符串、空列表、零值都会被评估为False

  2. 列表切割 会产生另一份全新列表,原列表引用不变;

  3. 当列表有起始索引,还有 步进 时候,应先做范围切割,再做步进;

  4. 对于 -1 步进 对字符串取反的技巧,只适应于 字节串 和 ASCII,Unicode不适合;

5. 推导式

# 1. 无参数映射 考虑 列表推导式
a = [1, 2, 3, 4, 5, 6]
squares = [x**2 for x in a]
print(squares)
>>>>> 
 [1, 4, 9, 16, 25, 36]

#内置map() 函数写法
squares = map(lambda x: x ** 2, a)

# 2. 涉及到原列表过滤时候,更方便
even_squares = [x ** 2 for x in a if x%2 == 0]
# 实现上述同样功能 需要map() 和filter() 函数使用
alt = map(lambda x: x**2, filter(lambda x: x%2 == 0,a))
assert even_squares == list(alt)

# 3. 字典dict() 和 集合set() 同样支持 推导式 comprehension 
# 对应的范围符号要改为 ‘{ }’

# 4. 矩阵处理 双层循环支持
#  矩阵 即是包含列表的列表,即二维列表
matrix = [[1,2,3], [4,5,6], [7,8,9]]
flat = [x for row in matrix for x in row]
print(flat)
>>>>>
[1, 2, 3, 4, 5, 6 ,7, 8, 9]

# 矩阵每个元素处理,如平方
# 先由外面'[]'推导,在进入第二层'[]' 
# 这样理解比较有条理性
squared = [[x**2 for x in row ] for row in matrix]

# 从矩阵中为3所整除的,且所在行元素之和大于等于10 单元格选择出来
filtered = [ [x for x in row if x % 3 == 0]
            for row in matrix if sum(row) >= 10]

6. 生成器

# 生成器表达式(generator expression) 相比于列表推导式(comprehension) 内存使用上有效率
# 用生成器表达式改写 推导式,针对文件操作 大数据操作  采用生成器
# 用'()' 替代 '[]' 就变成 生成器,返回 迭代器(iterator)
it = (len(x) for x in open('/tmp/leige_file.txt'))
print(it)
>>>  
   <generator object <genexpr> at 0x101b81480>

print(next(it))
print(next(it))
>>>
   100
   57
# 生成器 组合使用  执行效率表现很好
roots = ((x,x ** 0.5) for x in it)
print(next(roots))
>>>
   (15, 3.87298334)

7. enumerate() 与 range()

# range() 一般针对整数 序列进行迭代操作
# enumerate() 针对 字符串序列,需要自动生成索引下标,成对出现 使用
flavor_list =  ['vanilla', 'chocolate', 'pecan', 'strawberry']
# 列表写法
for i in range(len(flavor_list)):
    flavor = flavor_list[i]
    print('%d:%s'%(i+1, flavor))
# enumerate()写法
for i,flavor in enumerate(flavor_list):
    print('%d: %s' % (i+1,flavor))
#或 提供第二个参数,以指定开始计数时所用的值(默认为0)
for i,flavor in enumerate(flavor_list, 1):
    print('%d: %s' % (i,flavor))

8. Zip()函数

# zip() 平行遍历2个迭代器
# 一般两个迭代器存在关联,等长关系,不等长 以最短提前终止
# 示例
names = ['Cecilia', 'Lise', 'Marie']
letters = [len(n) for n in names]

longest_name = None
max_letters = 0

for name,count in zip(names, letters):
    if count > max_letters:
        longest_name = name
        max_letters = count

9. 异常模块组合

# try/except/else/finally
# finally 最后 必须执行的模块,常用来执行 清理收尾 或 关闭句柄
# exp
handle = open('/tmp/random_data.txt')
try:
    data = handle.read()
finally:
    handle.close()
# try except else 
# try 无异常,执行else  这方面往往会产生误解

10. 函数与异常

尽量用异常来表示特殊情况,而不要返回None;

原因在于:None 和 0 以及 空字符串之类的值,在条件表达式里都会评估为False。

yield 和可变位置参数 star args

11. 关键字参数和动态参数

关键字参数:

  1. 所有的位置参数,都可以按关键字传递;
  2. 位置参数必须出现在关键字参数之前;
  3. 关键字参数提高可读性,也可以为函数定义提供默认值;
  4. 为函数扩充有效参数提供了有效方式;
  5. 关键字参数设置,关键字参数调用。

动态默认值参数:

  1. 参数的默认值,只会在程序加载模块并读到本函数的定义时评估一次。对于{}和[]等动态值,可能会导致奇怪的行为。

  2. 动态值作为参数,应该默认值是None。

    # 程序执行日志示例
    def log(msg, when=None):
        '''
          Log a message with a timestamp
        '''
        when = datetime.now() if when else when
        print('%s:%s' % (when,message))

文章作者: 王磊
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 王磊 !
评论
  目录