Python中那些 Pythonic的写法详解


Posted in Python onJuly 02, 2019

前言

Martin(Bob大叔)曾在《代码整洁之道》一书打趣地说:当你的代码在做 Code Review 时,审查者要是愤怒地吼道:

“What the fuck is this shit?”
“Dude, What the fuck!”

等言辞激烈的词语时,那说明你写的代码是 Bad Code,如果审查者只是漫不经心的吐出几个

“What the fuck?”,

那说明你写的是 Good Code。衡量代码质量的唯一标准就是每分钟骂出“WTF” 的频率。

一份优雅、干净、整洁的代码通常自带文档和注释属性,读代码即是读作者的思路。Python 开发中很少要像 Java 一样把遵循某种设计模式作为开发原则来应用到系统中,毕竟设计模式只是一种实现手段而已,代码清晰才是最终目的,而 Python 灵活而不失优雅,这也是为什么 Python 能够深受 geek 喜爱的原因之一。

上次写了一篇:如何更优雅地写python代码,今天就接着这个话题写点 Python 中那些 Pythonic 的写法,希望可以抛砖引玉。

1、链式比较操作

age = 18
if age > 18 and age < 60:
print("young man")

pythonic

if 18 < age < 60:
print("young man")

理解了链式比较操作,那么你应该知道为什么下面这行代码输出的结果是 False。

>>> False == False == True 
False

2、if/else 三目运算

if gender == 'male':
text = '男'
else:
text = '女'

pythonic

text = '男' if gender == 'male' else '女'

在类C的语言中都支持三目运算 b?x:y,Python之禅有这样一句话:

“There should be one-- and preferably only one --obvious way to do it. ”。

能够用 if/else 清晰表达逻辑时,就没必要再额外新增一种方式来实现。

3、真值判断

检查某个对象是否为真值时,还显示地与 True 和 False 做比较就显得多此一举,不专业

if attr == True:
do_something()
if len(values) != 0: # 判断列表是否为空
do_something()

pythonic

if attr:
do_something()
if values:
do_something()

真假值对照表:

类型 False True

布尔 False (与0等价) True (与1等价)

字符串 ""( 空字符串) 非空字符串,例如 " ", "blog"

数值 0, 0.0 非0的数值,例如:1, 0.1, -1, 2

容器 [], (), 至少有一个元素的容器对象,例如:[0], (None,), ['']

None None 非None对象

4、for/else语句

for else 是 Python 中特有的语法格式,else 中的代码在 for 循环遍历完所有元素之后执行。

flagfound = False
for i in mylist:
if i == theflag:
flagfound = True
break
process(i)
if not flagfound:
raise ValueError("List argument missing terminal flag.")

pythonic

for i in mylist:
if i == theflag:
break
process(i)
else:
raise ValueError("List argument missing terminal flag.")

5、字符串格式化

s1 = "foofish.net"
s2 = "vttalk"
s3 = "welcome to %s and following %s" % (s1, s2)

pythonic

s3 = "welcome to {blog} and following {wechat}".format(blog="foofish.net", wechat="vttalk")

很难说用 format 比用 %s 的代码量少,但是 format 更易于理解。

“Explicit is better than implicit --- Zen of Python”

6、列表切片

获取列表中的部分元素最先想到的就是用 for 循环根据条件提取元素,这也是其它语言中惯用的手段,而在 Python 中还有强大的切片功能。

items = range(10)
# 奇数
odd_items = []
for i in items:
if i % 2 != 0:
odd_items.append(i)
# 拷贝
copy_items = []
for i in items:
copy_items.append(i)

pythonic

# 第1到第4个元素的范围区间
sub_items = items[1:4]
# 奇数
odd_items = items[1::2]
#拷贝
copy_items = items[::] 或者 items[:]

列表元素的下标不仅可以用正数表示,还是用负数表示,最后一个元素的位置是 -1,从右往左,依次递减。

--------------------------
| P | y | t | h | o | n |
--------------------------
 0 1 2 3 4 5 
 -6 -5 -4 -3 -2 -1
--------------------------

7、善用生成器

def fib(n):
a, b = 0, 1
result = []
while b < n:
result.append(b)
a, b = b, a+b
return result

pythonic

def fib(n):
a, b = 0, 1
while a < n:
yield a
a, b = b, a + b

上面是用生成器生成费波那契数列。生成器的好处就是无需一次性把所有元素加载到内存,只有迭代获取元素时才返回该元素,而列表是预先一次性把全部元素加载到了内存。此外用 yield 代码看起来更清晰。

8、获取字典元素

d = {'name': 'foo'}
if d.has_key('name'):
print(d['name'])
else:
print('unkonw')

pythonic

d.get("name", "unknow")

9、预设字典默认值

通过 key 分组的时候,不得不每次检查 key 是否已经存在于字典中。

data = [('foo', 10), ('bar', 20), ('foo', 39), ('bar', 49)]
groups = {}
for (key, value) in data:
if key in groups:
groups[key].append(value)
else:
groups[key] = [value]

pythonic

# 第一种方式
groups = {}
for (key, value) in data:
groups.setdefault(key, []).append(value)

# 第二种方式
from collections import defaultdict
groups = defaultdict(list)
for (key, value) in data:
groups[key].append(value)

10、字典推导式

在python2.7之前,构建字典对象一般使用下面这种方式,可读性非常差

numbers = [1,2,3]
my_dict = dict([(number,number*2) for number in numbers])
print(my_dict) # {1: 2, 2: 4, 3: 6}

pythonic

numbers = [1, 2, 3]
my_dict = {number: number * 2 for number in numbers}
print(my_dict) # {1: 2, 2: 4, 3: 6}

# 还可以指定过滤条件
my_dict = {number: number * 2 for number in numbers if number > 1}
print(my_dict) # {2: 4, 3: 6}

字典推导式是python2.7新增的特性,可读性增强了很多,类似的还是列表推导式和集合推导式。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
浅析python 内置字符串处理函数的使用方法
Jun 11 Python
Python中使用PIPE操作Linux管道
Feb 04 Python
Python3.x中自定义比较函数
Apr 24 Python
简述Python2与Python3的不同点
Jan 21 Python
Python求两个圆的交点坐标或三个圆的交点坐标方法
Nov 07 Python
用python标准库difflib比较两份文件的异同详解
Nov 16 Python
对python 生成拼接xml报文的示例详解
Dec 28 Python
Python3 文章标题关键字提取的例子
Aug 26 Python
Python面向对象之继承原理与用法案例分析
Dec 31 Python
Python实现银行账户资金交易管理系统
Jan 03 Python
python的setattr函数实例用法
Dec 16 Python
pytorch 如何把图像数据集进行划分成train,test和val
May 31 Python
python 中如何获取列表的索引
Jul 02 #Python
python 缺失值处理的方法(Imputation)
Jul 02 #Python
Python 读取串口数据,动态绘图的示例
Jul 02 #Python
python中对数据进行各种排序的方法
Jul 02 #Python
Python虚拟环境的原理及使用详解
Jul 02 #Python
python输出电脑上所有的串口名的方法
Jul 02 #Python
如何更优雅地写python代码
Jul 02 #Python
You might like
解析coreseek for sphinx的使用
2013/06/21 PHP
PHP命名空间namespace用法实例分析
2016/09/27 PHP
Laravel框架Auth用户认证操作实例分析
2019/09/29 PHP
jQuery.validate 常用方法及需要注意的问题
2013/03/20 Javascript
javascript中onclick(this)用法介绍
2013/04/19 Javascript
JavaScript生成二维码图片小结
2015/12/27 Javascript
js将json格式的对象拼接成复杂的url参数方法
2016/05/25 Javascript
jQuery插件DataTable使用方法详解(.Net平台)
2016/12/22 Javascript
微信小程序 setData使用方法及常用错误解决办法
2017/05/11 Javascript
原生JS实现简单的无缝自动轮播效果
2018/09/26 Javascript
Vue 样式绑定的实现方法
2019/01/15 Javascript
ES6的异步操作之promise用法和async函数的具体使用
2019/12/06 Javascript
node爬取新型冠状病毒的疫情实时动态
2020/02/06 Javascript
vue-axios同时请求多个接口 等所有接口全部加载完成再处理操作
2020/11/09 Javascript
寻找网站后台地址的python脚本
2014/09/01 Python
Python THREADING模块中的JOIN()方法深入理解
2015/02/18 Python
Python捕捉和模拟鼠标事件的方法
2015/06/03 Python
python抓取并保存html页面时乱码问题的解决方法
2016/07/01 Python
Python加载带有注释的Json文件实例
2018/05/23 Python
在python中利用最小二乘拟合二次抛物线函数的方法
2018/12/29 Python
提升Python程序性能的7个习惯
2019/04/14 Python
Python何时应该使用Lambda函数
2019/07/02 Python
pytorch 共享参数的示例
2019/08/17 Python
python 正则表达式贪婪模式与非贪婪模式原理、用法实例分析
2019/10/14 Python
python seaborn heatmap可视化相关性矩阵实例
2020/06/03 Python
CSS3 Media Queries详细介绍和使用实例
2014/05/08 HTML / CSS
洛杉矶生活休闲而精致的基础品牌:Mika Jaymes
2018/01/07 全球购物
美国转售二手商品的电子商务平台:BLINQ
2018/12/13 全球购物
我有一个梦想演讲稿
2014/05/05 职场文书
单位工资证明范本
2015/06/12 职场文书
先进个人主要事迹怎么写
2015/11/04 职场文书
2016开学第一课心得体会
2016/01/23 职场文书
入党申请书格式
2019/06/20 职场文书
Golang中interface{}转为数组的操作
2021/04/30 Golang
总结高并发下Nginx性能如何优化
2021/11/01 Servers
Win11筛选键导致键盘失灵怎么解决? Win11关闭筛选键的技巧
2022/04/08 数码科技