有些位置可能翻译理解的不到位,各位看官如有疑问,欢迎留言赐教。

Pythonic Thinking

大家经常用Pythonic来形容python语法风格的编程方式:简单优美,没有之一;通过import this查看Python之禅。

使用python之前需要明确使用的是python2 or python3。推荐使用python3。


PEP8编码风格指南

缩进留白Whitespace

  • python通过强制缩进的方式,控制字代码块;每次缩进使用4个空格符;

  • 单行代码不宜超过79个字符,当使用\分行显示时,换行的部分应该缩进4个空格位。

  • 文件中,函数和类之间空2行;类中,方法之间空1行;

  • 列表索引访问、函数调用、关键字参数赋值时不应该使用空格;变量赋值间应该空一格;

命名

  • 函数名、变量名、类的属性名采用:小写字母加下划线的方式;

  • 保护对象属性命名采用:下划线开头加小写字母加下划线的方式;

  • 私有对象属性命名采用:双下划线开头加小写字母加下划线的方式;

  • 类名、异常命名采用:驼峰体的方式;

  • 常量命名采用:全大写字母的方式;

  • 类中对象自己使用 self, 类自己使用 cls

表达式&声明

  • 判断对象是否不相等使用 if a is not b 而不使用 if not a is b

  • 判断对象是否为空使用 if not a, 而不使用 if len(a) == 0

  • 判断对象不为空使用 if a

  • 当子代码块只有一行时,不要在写在一块

if True: print('hello world')   # 不推荐,建议换行
  • 导入模块时,在文件顶部导入;导入时应该使用完成的导入路径
from bar import foo
import foo # 不推荐
  • 导入模块的顺序:标准库,三方库,自己的库;在每一等级内都按字母顺序导入

区别:bytes & str & unicode

  • Python3中,bytes指的是包含8-bit的二进制数据;str指的是Unicode字符。bytes和str是两个完全独立的对象;

  • Python2中,str指的是包含8-bit的二进制数据;unicode指的是Unicode字符;str和unicode处理7-bit的ASCII时是相同的。

# Python3中,定义函数将bytes or str转换成str
def to_str(bytes_or_str):
if isinstance(bytes_or_str, bytes):
value = bytes_or_str.decode(‘utf-8’)
else:
value = bytes_or_str
return value # Instance of str # Python3中,定义函数将bytes or str转换成bytes
def to_bytes(bytes_or_str):
if isinstance(bytes_or_str, str):
value = bytes_or_str.encode(‘utf-8’)
else:
value = bytes_or_str
return value # Instance of bytes
  • Python3中,文件操作时,文本文件用t模式,二进制文件用b模式;

函数优于复杂的表达式

切片Slice

a = [‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’, ‘g’, ‘h’]
# a[start:end]
a[:] # [‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’, ‘g’, ‘h’]
a[:5] # [‘a’, ‘b’, ‘c’, ‘d’, ‘e’]
a[:-1] # [‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’, ‘g’]
a[4:] # [‘e’, ‘f’, ‘g’, ‘h’]
a[-3:] # [‘f’, ‘g’, ‘h’]
a[2:5] # [‘c’, ‘d’, ‘e’]
a[2:-1] # [‘c’, ‘d’, ‘e’, ‘f’, ‘g’]
a[-3:-1] # [‘f’, ‘g’]
  • 切片的使用遵循 '顾头不顾尾'的基本原则;

  • startend不指定表示从头切或切到尾;都不指定则表示全部拷贝一份,切片属于浅拷贝;

  • 使用切片不会出现索引越界的问题,如a[:20]表示切前20个元素;

  • start或end为负数,表示倒数第几个,同样遵循 '顾头不顾尾'的基本原则;

  • 如果想要从头切不要提供start,切到尾时不要提供end,如a[:5],切前5个

  • 切片用于赋值时,表示切片的那些位置用新的值覆盖

a[2:7] = [99, 22, 14]	# a = [‘a’, ‘b’, 99, 22, 14, ‘h’]

注意:列表切片赋值修改的是列表内元素的绑定关系,列表对象的内存地址没变。(旧瓶子换了新酒)

b = a
a[:] = [101, 102, 103]
print (a is b) # True
  • 切片时尽可能避免同时使用三个参数:a[start:end:step],这样很很容易让人头晕(我也是醉了)a[2:5:-2]

  • step表示间隔几个切一片,是步长的意思。步长为负数表示倒着切;最好不好使用倒着切;


列表生成式 List Comprehensions

a = [x for x in range(10)]
aquares = [x**2 for x in a]
  • 尽量使用列表生成式而不是用map()和filter()内置函数。因为map()和filter()一般要配合匿名函数的使用,不简洁。
squares = map(lambda x: x ** 2, a)
even_squares = [x**2 for x in a if x % 2 == 0]
alt = map(lambda x: x**2, filter(lambda x: x % 2 == 0, a)) # 表达式很繁琐
assert even_squares == list(alt)
  • 字典和集合等也有对应的生成式。

  • 列表生成式可以多层嵌套,可以后接判断条件;当列表生成式出现超过两层嵌套或者多个条件判断时,不建议使用,建议改写成包含iffor的函数。

  • 数据量过大时,使用表达式生成器(generator expressions )替换列表生成式的使用,减少内存消耗。

  • 多使用 enumerate 少使用 range

for i in range(len(flavor_list)):	# 需要获取列表长度
flavor = flavor_list[i] # 通过索引取值
print(‘%d: %s’ % (i + 1, flavor)) for i, flavor in enumerate(flavor_list, 1):
print(‘%d: %s’ % (i, flavor))
  • 同时并行循环两个列表使用zip

  • 避免在while或者 for循环体外后接else代码块(pep8规范)

  • 充分捕获异常:try|except|else|finally


函数

函数返回值不推荐使用None

  • 函数返回值有具体意义时,不推荐返回None;因为调用函数的对象使用判断时无法区分出None、0、[];应该采用在函数体中捕获异常替代None。

闭包函数只读外部函数作用域变量

  • 闭包函数可以引用它定义时外部函数作用域的变量a,但不可以修改赋值修改该变量,因为修改的操作会在闭包函数的局部作用域内增加一个新的变量而不是修改器外部函数作用域内的变量。
  • 但非要将在闭包寒素内修改外部作用域的变量也可以,但不推荐(容易出难以排查的bug)。
  • python3中通过nonlocal 语法声明接下来要操作的边外部函数作用域的a;python2没有nonlocal语法,是通过将变量定义成可变数据类型,比如列表,在闭包函数里通过a[0]修改。

推荐使用生成器而不是直接返回一个列表

  • 当数据序列数据量庞大时,使用列表粉肠消耗内存,而生成器只是保存序列的算法,每次调用时返回一个。

使用不定长度的位置参数*args优化函数传参调用时的简洁性

  • 函数定义时使用*args可以接收多个位置参数,args以元组的形式保存传进来的多个数据;
  • 函数调用时可以通过*operator解压可迭代对象operator中的序列数据,按位置参数赋值给形参;
  • 调用函数传实参时*operator,operator避免使用生成器否则可能会消耗大量内存导致程序崩溃;
  • 使用*args的缺点是:函数未来增加新位置行参时很容易出bug且很难排查。

建议使用关键字参数传参给形参

  • 关键字传参可以不按照位置顺序,只要每个形参都有被赋值即可;可以同时使用位置传参和关键字传参,但关键字传参要放在位置传参后面,且每个形参只能被赋值一次;
  • 关键字传参好处一:每个参数表示的意义清晰明了;第二个好处:导致出现了函数定义时的默认形参;
  • 第三个好处:向下兼容性,更新函数功能后(新增了默认参数)不会影响老用户使用该函数的调用接口;老用户使用默认的值,新用户可以使用默认参数指定新的值;
def flow_rate(weight_diff, time_diff, period=1, units_per_kg=1):
return ((weight_diff / units_per_kg) / time_diff) * period
# 老用户使用时不知道函数定义代码已经修改了,依然使用可以旧的两个参数传参
# 而新用户知道新增的两个参数表示意思,需要时指定自定义值即可
pounds_per_hour = flow_rate(weight_diff, time_diff, period=3600, units_per_kg=2.2)
  • 这种向下兼容性对于使用*args接收参数的函数很重要;
  • 默认参数最好使用关键字传参而不用位置参数传参。

使用None和文档注释的方式为函数参动态的参数

  • 默认参数只会在函数定义时赋值一次,如果默认参数等于{}或[],这将导致后面所有的函数调用者访问的都是同一个字典或列表的内存地址;
  • 使用默认值为None,再加文档注释的方式实现动态参默认参数
# 记录消息的打印时间
def log(message, when=datetime.now()):
print(‘%s: %s’ % (when, message)) log(‘Hi there!’)
sleep(0.1)
log(‘Hi again!’)
>>>
2014-11-15 21:10:10.371432: Hi there!
2014-11-15 21:10:10.371432: Hi again! # 两次的时间是相同的
# 这是因为when这个默认参数在函数定义的瞬间就被赋值了,以后每次调用使用的都是一个相同的值;
# 如果想要时时获得打印消息的时间,使用默认参数为None的方式
def log(message, when=None):
"""
Log a message with a timestamp.
Args:
message: Message to print.
when: datetime of when the message occurred.
Defaults to the present time.
"""
when = datetime.now() if when is None else when
print(‘%s: %s’ % (when, message))

限制函数调用者使用关键字参数为函数传参

  • python3中函数定时,参数列表中添加 * ,其后的参数必须使用关键字传参,否则会报TypeError 的错误;
  • python2中没有该语法,若非要这样做可以使用**kwargs加手动抛出TypeError的错误。

update to 20200323

大佬总结的很好,直接引用学习了

Effective Python读书笔记的更多相关文章

  1. Web Scraping with Python读书笔记及思考

    Web Scraping with Python读书笔记 标签(空格分隔): web scraping ,python 做数据抓取一定一定要明确:抓取\解析数据不是目的,目的是对数据的利用 一般的数据 ...

  2. Effective STL 读书笔记

    Effective STL 读书笔记 标签(空格分隔): 未分类 慎重选择容器类型 标准STL序列容器: vector.string.deque和list(双向列表). 标准STL管理容器: set. ...

  3. Effective STL读书笔记

    Effective STL 读书笔记 本篇文字用于总结在阅读<Effective STL>时的笔记心得,只记录书上描写的,但自己尚未熟练掌握的知识点,不记录通用.常识类的知识点. STL按 ...

  4. effective c++读书笔记(一)

    很早之前就听过这本书,找工作之前读一读.看了几页,个人感觉实在是生涩难懂,非常不符合中国人的思维方式.之前也有博主做过笔记,我来补充一些自己的理解. 我看有人记了笔记,还不错:http://www.3 ...

  5. Effective Java读书笔记完结啦

    Effective Java是一本经典的书, 很实用的Java进阶读物, 提供了各个方面的best practices. 最近终于做完了Effective Java的读书笔记, 发布出来与大家共享. ...

  6. Effective java读书笔记

    2015年进步很小,看的书也不是很多,感觉自己都要废了,2016是沉淀的一年,在这一年中要不断学习.看书,努力提升自己 计在16年要看12本书,主要涉及java基础.Spring研究.java并发.J ...

  7. Effective Python2 读书笔记3

    Item 22: Prefer Helper Classes Over Bookkeeping with Dictionaries and Tuples For example, say you wa ...

  8. Effective Python2 读书笔记2

    Item 14: Prefer Exceptions to Returning None Functions that returns None to indicate special meaning ...

  9. Effective Python2 读书笔记1

    Item 2: Follow the PEP 8 Style Guide Naming Naming functions, variables, attributes lowercase_unders ...

随机推荐

  1. Css兼容性大全

    知识有所欠缺  疯狂脑补抄袭经验中... 兼容性处理要点1.DOCTYPE 影响 CSS 处理 2.FF: 设置 padding 后, div 会增加 height 和 width, 但 IE 不会, ...

  2. TCP并发、GIL全局锁、多线程讨论

    TCP实现并发 #client客户端 import socket client = socket.socket() client.connect(('127.0.0.1',8080)) while T ...

  3. lsync+rsync 实时同步(ubuntu16.04系统)

    1.同步端需要安装 lsync/rsyncapt-get install lsyncd rsync2.生成ssh公钥,粘贴到目标机器里面3.创建配置文件mkdir /etc/lsyncdcat /et ...

  4. WEB前端工程师简历

    一个热爱前端的工程师 关于我 我的作品 ZENRON 关于我 求职意向 作品集 技术掌握 我的经历 联系我 关于我 英语/CET-4 坐标/苏州 状态/求职 我叫Zenron, 现居住苏州, 是一名前 ...

  5. 【转载】Oracle Spatial中SDO_Geometry详细说明

    转载只供个人学习参考,查看请前往原出处:http://www.cnblogs.com/upDOoGIS/archive/2009/05/20/1469871.html 相关微博:oracle 创建SD ...

  6. 一天速成Python教程

    一.Python基础 Python是对象有类型,变量无类型的动态类型语言,追求简单优雅易读.可以在终端中逐行运行,也可以编写成大型的面向对象的工程.在开始写之前,注意Python 2.X中,开头要写上 ...

  7. scrapy爬虫-代理IP中间件

    class ProxyDownloaderMiddleware(object): # Not all methods need to be defined. If a method is not de ...

  8. CentOS7 安装python 3.5 及 pip安装

    1.CentOS7 安装Python 的依赖包 # yum install -y zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-d ...

  9. Go-数据类型以及变量,常量,函数,包的使用

    Go-数据类型以及变量,常量,函数,包的使用 一.数据类型 1.字符串类型 string -双引号包裹的:"xxx" -反引号包裹,可以换行, 注意: 区别于python,是没有单 ...

  10. Java基础:浅谈数据输入流/数据输出流《DataInputstream类与DataOutputstream类》

     一.理论概述 数据输入/输出流(DataInputStream类与DataOutputStream类) 允许应用程序以与机器无关的方式从底层输入流中读取基本Java数据类型. 说白了就是,当读取一个 ...