《Effective Python》笔记 第一章-培养Pythonic思维
阅读Effective Python(第二版)的一些笔记。
第3条 了解bytes和str的区别
可以直接参考:https://sanyuesha.com/2016/11/06/python-string-unicode/
第4条 用支持插值的f-string取代C风格的格式字符串与str.format方法
C风格的字符串格式化
>>> "name:%s, age:%d" % ("abc", 99) 'name:abc, age:99'
缺点
- 左侧指定值的类型或者顺序发生变化时,可能发生类型不兼容的问题,需要校验两边的类型和数量一致
- 左侧的字符串模板和右侧的参数使用%拼接,如果参数过多时,代码就会比较长(混乱),需要拆分多行
- 左侧要重复同一个值多次,那么右侧需要重复同样的次数
str的format方法
>>> "name:{}, age:{}".format("abc", 99) 'name:abc, age:99'
- 与C风格的字符串格式化类似
- 同样需要保证左右两侧的参数保持一致
插值格式字符串
python 3.6支持的新特性,使用f
前缀,模板中可以直接使用{field_name}
来获取field_name的值,不用C风格那样在右侧指定参数。
>>> name="abc" >>> age=99 >>> formatted_str = f"name:{name}, age:{age}" >>> print(formatted_str) name:abc, age:99
如果{field_name}的field_name没有定义,则报错NameError。
第5条 用辅助函数取代复杂的表达式
语法简洁的Python虽然可以写出很多浓缩的句式,比如if/else三元表达式、for/in列表生成式,lambda表达式,但应该避免让这样的写法把表达式弄得太复杂。
如果你发现表达式越写越复杂,那就应该考虑把它拆分成多个部分,并且把这套逻辑写到辅助函数里面。这样虽然要多编几行代码,但可以让程序更加清晰,所以总体来说还是值得的。
第6条 把数据结构直接拆分到多个变量里,不要专门通过下标访问
使用unpacking方式替换通过下标访问
data = [ ("abc", 66, "beijing"), ("xyz", 88, "shanghai") ] # 使用下标访问 for item in data: name = item[0] age = item[1] addr = item[2] print("name:{}, age:{}, addr:{}".format(name, age, addr)) # 通过unpacking方式 for item in data: name, age, addr = item print("name:{}, age:{}, addr:{}".format(name, age, addr))
使用enumerate + unpacking迭代列表
如果要遍历列表的时候,同时打印元素的index,那么习惯C风格的循环遍历列表的方式,一般会写为下面这样:
# 迭代-旧方式 size = len(data) for index in range(0, size): item = data[index] print("index:%s, data:%s" % (index, item)) # 便捷方式 for index, item in enumerate(data): print("index:%s, data:%s" % (index, item))
第7条 尽量用enumerate取代range
尽量避免使用for循环中使用下标访问集合元素,应改用enumerate进行迭代
data = [11, 22, 33, 44, 55] # 使用下标形式访问 for i in range(len(data)): print("index:{}, value:{}".format(i, data[i])) # index:1, value:11 # index:2, value:22 # 使用enumerate进行迭代,起始序号为0 for i, val in enumerate(data): print("index:{}, value:{}".format(i, val)) # index:1, value:11 # index:2, value:22 # 起始需要为4 for i, val in enumerate(data, 4): print("index:{}, value:{}".format(i, val)) # index:4, value:11 # index:5, value:22
第8条 用zip函数同时遍历两个迭代器
有时候,需要同步遍历两个列表进行操作时,下面是比较简单的做法:
data_1 = [1, 2, 3] data_2 = ["x", "y", "z"] for i in range(len(data_1)): item_1 = data_1[i] item_2 = data_2[i] print("item_1:{}, item_2:{}".format(item_1, item_2)) # item_1:1, item_2:x # item_1:2, item_2:y # item_1:3, item_2:z
另外一种比较方便的方式就是使用zip(),zip函数可以接受多个可迭代的集合,然后每次迭代都会从这些集合中取一个元素,示例如下:
for item_1, item_2 in zip(data_1, data_2): print("item_1:{}, item_2:{}".format(item_1, item_2)) # item_1:1, item_2:x # item_1:2, item_2:y # item_1:3, item_2:z
需要注意:
- zip函数在迭代的时候,只要其中一个集合遍历结束,那么就不再往下走了;
- 如果希望遍历时,以元素最多的集合为基准进行遍历,那么可以使用itertools模块的zip_longest()函数。
示例如下:
data_3 = [1, 2, 3, 4] data_4 = ["x", "y", "z"] for item_1, item_2 in zip(data_3, data_4): print("item_1:{}, item_2:{}".format(item_1, item_2)) # item_1:1, item_2:x # item_1:2, item_2:y # item_1:3, item_2:z from itertools import izip_longest # python2 # from itertools import zip_longest # python3 for item_1, item_2 in izip_longest(data_3, data_4): print("item_1:{}, item_2:{}".format(item_1, item_2)) # item_1:1, item_2:x # item_1:2, item_2:y # item_1:3, item_2:z # item_1:4, item_2:None
第9条 不要在for与while循环后面写else块
python中支持for循环和while循环后面加else块,他的功能有点绕,所以不要使用这种写法。
- 在for循环或者while循环从头到尾执行完没有中断,或者没有进入循环,就会执行else块代码;
data = [1, 2, 3] for i in data: if i >= 4: print("循环发生中断,else代码块不会执行") break else: print("循环从头到尾执行完毕了,接着执行else代码块") # 循环从头到尾执行完毕或者未进入循环,接着执行else代码块
- 当循环执行过程中,发生了break或者return,循环被中断了,那么else就不会执行;
# 修改数据,让循环发生中断 data = [1, 2, 3, 4, 5] for i in data: if i >= 4: print("循环发生中断,else代码块不会执行") break else: print("循环从头到尾执行完毕或者未进入循环,接着执行else代码块") # 循环发生中断,else代码块不会执行
第10条 用赋值表达式减少重复代码
代码中对于某个变量进行判断操作是非常频繁的,有时候这个变量其实没有多大意义,只是为了确定走哪个分支,仅仅用在判断或者仅仅用在if/else里面;
比如下面判断工资wage属性,进行不同的操作
person = Person("小明", "male", 50000) # 直接使用属性 if person.wage > 10000: print("wage:{}w".format(person.wage / 10000)) else: print("wage:{}k".format(person.wage / 1000)) # 将属性赋值给变量,后面可以直接会用变量 wage = person.wage if wage > 10000: print("wage:{}w".format(wage / 10000)) else: print("wage:{}k".format(wage / 1000)) # 其他代码,并且wage变量未使用过
直接使用属性的的形式,当参数名称比较长的时候不太方便;
将属性赋值给一个变量,可能会让人觉得wage变量是一个很重要的变量,实际上可能只是用来判断走哪个分支,后面根本没有用过。
Python 3.8的一个新特性:赋值表达式,使用var_name := value
这种形式进行赋值,用法如下:
if (wage := person.wage) > 10000: print("wage:{}w".format(wage / 10000)) else: print("wage:{}k".format(wage / 1000)) print(wage) # 仍旧能访问到wage变量
使用赋值表达式:
- 可以省一行代码;
- 压低变量的地位,明确wage的使用范围(注意外部其实还是可以访问到赋值表达式的变量)
- 可以模拟switch/case、do/while的写法``
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 字符编码:从基础到乱码解决