如何写出 Pythonic 的代码?

写在开头:

其实,这是一个引流帖,个人技术博客网址请访问 BYA’s Blog 或直接搜索框输入 http://bya.cool
里面目前主要分享一些关于Python基础&进阶、Linux、golang、echarts可视化、主题阅读等 笔记总结,欢迎评论留言~~

什么是Pythonic?

Pythonic就是以Python的方式写出简洁、优美的代码。

The Zen of Python(Python之禅) 执行 import this 查看

Pythonic vs Non-Pythonic common cases

**P 代表 Pythonic, NP代表 Non-Pythonic。**相比于NP,P的写法简练,明确,优雅,绝大部分时候执行效率高,代码越少也就越不容易出错。好的程序员在写代码时,应该追求代码的正确性,简洁性和可读性,这恰恰就是pythonic的精神所在。

变量交换赋值

#P
a,b = b,a

#NP
tmp = a
a = b
b = tmp

Unpacking

#P
l = ['David', 'Pythonista', '+1-514-555-1234']
first_name, last_name, phone_number = l
# Python 3 Only
first, *middle, last = another_list

#NP
l = ['David', 'Pythonista', '+1-514-555-1234']
first_name = l[0]
last_name = l[1]
phone_number = l[2] 

链式比较

#P 
a = 3
b = 1
1 <= b <= a < 10 #True

#NP
b >= 1 and b <= a and a < 10 #True

使用操作符in

#P
if fruit in ["apple", "orange", "berry"]:
 # 使用 in 更加简洁

#NP
if fruit == "apple" or fruit == "orange" or fruit == "berry":
 # 多次判断 

真值测试

#P
name = 'Tim'
langs = ['AS3', 'Lua', 'C']
info = {'name': 'Tim', 'sex': 'Male', 'age':23 }    
 
if name and langs and info:
    print('All True!')  #All True!

#NP
if name != '' and len(langs) > 0 and info != {}:
    print('All True!') #All True!

P的写法就是对于任意对象,直接判断其真假,无需写判断条件,这样既能保证正确性,又能减少代码量。

TrueFalse
任意非空字符串空字符串 ''
任意非0数字数字 0
任意非空容器空的容器 []``()``{}``set()
其他任意非FalseNone

字符串反转

#P
def reverse_str(s):
    return s[::-1]

#NP
def reverse_str(s):
    t = ''
    for x in range(len(s)-1,-1,-1):
        t += s[x]
    return t

#如果用于检测回文,就是一句话input == input[::-1]

字符串列表的连接

#P
strList = ["Python", "is", "good"]  
res =  ' '.join(strList) #Python is good # 没有额外的内存分配

#NP
res = ''
for s in strList:
    res += s + ' ' #每次赋值都丢弃以前的字符串对象, 生成一个新对象
#Python is good 
#最后还有个多余空格

string.join()常用于连接列表里的字符串,相对于NP,P的方式十分高效,且不会犯错。

列表求和,最大值,最小值,乘积

#P
numList = [1,2,3,4,5]   
 
sum = sum(numList)  #sum = 15
maxNum = max(numList) #maxNum = 5
minNum = min(numList) #minNum = 1
from operator import mul
from functools import reduce #Python3 中 reduce被取消了,要从functools中导入
prod = reduce(mul, numList, 1) #prod = 120 默认值传1以防空列表报错

#NP
sum = 0
maxNum = -float('inf')
minNum = float('inf')
prod = 1
for num in numList:
    if num > maxNum:
        maxNum = num
    if num < minNum:
        minNum = num
    sum += num
    prod *= num
# sum = 15 maxNum = 5 minNum = 1 prod = 120

列表推导式

#P
l = [x*x for x in range(10) if x % 3 == 0]
#l = [0, 9, 36, 81]

#NP
l = []
for x in range(10):
    if x % 3 == 0:
        l.append(x*x)
#l = [0, 9, 36, 81]

列表推导嵌套

#P
gen = (item for sl in nested_list if list_condition(sl) 
	for item in sl if item_condition(item))
for item in gen:
 # do something...

#NP
for sub_list in nested_list:
	if list_condition(sub_list):
		for item in sub_list:
			if item_condition(item):
				# do something... 

循环嵌套

#P
from itertools import product
for x, y, z in product(x_list, y_list, z_list):
	# do something for x, y, z
    
#NP
for x in x_list:
	for y in y_list:
		for z in z_list:
			# do something for x & y 

字典键值列表

#P
for key in my_dict:
 # my_dict[key] ...

#NP
for key in my_dict.keys():
 # my_dict[key] ... 

只有当循环中需要更改key值的情况下,我们需要使用 my_dict.keys()

字典键值判断

#P
if key in my_dict:
 # ...do something with d[key]

#NP
if my_dict.has_key(key):
 # ...do something with d[key] 

字典 get 和 setdefault 方法

#P
navs = {}
for (portfolio, equity, position) in data:
	# 使用 get 方法
	navs[portfolio] = navs.get(portfolio, 0) + position * prices[equity]
	# 或者使用 setdefault 方法
	navs.setdefault(portfolio, 0)
	navs[portfolio] += position * prices[equity]

#NP
navs = {}
for (portfolio, equity, position) in data:
	if portfolio not in navs:
	navs[portfolio] = 0
	navs[portfolio] += position * prices[equity]


字典的默认值

#P
dic = {'name':'Tim', 'age':23}  
 
dic['workage'] = dic.get('workage',0) + 1
#dic = {'age': 23, 'workage': 1, 'name': 'Tim'}

#NP
if 'workage' in dic:
    dic['workage'] += 1
else:
    dic['workage'] = 1
#dic = {'age': 23, 'workage': 1, 'name': 'Tim'}

dict的get(key,default)方法用于获取字典中key的值,若不存在该key,则将key赋默认值default。
P相比NP的写法少了if...else...

for...else...语句

#P
for x in range(1,5):
    if x == 5:
        print('find 5')
        break
else:
    print('can not find 5!')
#can not find 5!

#NP
find = False
for x in range(1,5):
    if x == 5:
        find = True
        print('find 5')
        break
if not find:
    print('can not find 5!')
#can not find 5!


for...else...的else部分用来处理没有从for循环中断的情况。有了它,我们不用设置状态变量来检查是否for循环有break出来,简单方便。

三元符的替代

#P
a = 3   
 
b = 2 if a > 2 else 1
#b = 2

#NP
if a > 2:
    b = 2
else:
    b = 1
#b = 2

enumerate,带有索引位置的集合遍历

#P
array = [1, 2, 3, 4, 5]

for i, e in enumerate(array, 0):
    print(i, e)
# 0 1
# 1 2
# 2 3
# 3 4
# 4 5

#NP
for i in range(len(array)):
    print(i, array[i])
#0 1
#1 2
#2 3
#3 4
#4 5

使用enumerate可以一次性将索引和值取出,避免使用索引来取值,而且enumerate的第二个参数可以调整索引下标的起始位置,默认为0。

使用zip创建键值对

#P
keys = ['Name', 'Sex', 'Age']
values = ['Tim', 'Male', 23]
 
dic = dict(zip(keys, values))
#{'Age': 23, 'Name': 'Tim', 'Sex': 'Male'}

#NP
dic = {}
for i,e in enumerate(keys):
    dic[e] = values[i]
#{'Age': 23, 'Name': 'Tim', 'Sex': 'Male'}

zip方法返回的是一个元组,用它来创建键值对,简单明了。

表达式单行显示

#P
print('one')
print('two')

if x == 1:
	print('one')

cond1 = <complex comparison>
cond2 = <other complex comparison>
if cond1 and cond2:
    # do something

#NP
print('one'); print('two')

if x == 1: print('one')

if <complex comparison> and <other complex comparison>:
    # do something

使用 with 处理文件

#P
with open("some_file.txt") as f:
	data = f.read()
	# 其他文件操作...

#NP
f = open("some_file.txt")
try:
	data = f.read()
	# 其他文件操作..
finally:
	f.close()

使用 with 忽视异常(仅限Python 3)

#P
from contextlib import ignored # Python 3 only
with ignored(OSError):
	os.remove("somefile.txt")
    
#NP
try:
	os.remove("somefile.txt")
except OSError:
	pass

使用 with 处理加锁

#P
import threading
lock = threading.Lock()
with lock:
     # 互斥操作...
        
#NP
import threading
lock = threading.Lock()
lock.acquire()
try:
	# 互斥操作...
finally:
	lock.release()

拓展阅读

Code Like a Pythonista: Idiomatic Python–译

Code Like a Pythonista: Idiomatic Python(原文)

让你的Python代码更加 pythonic

《编码之前碎碎念(工程实践) - python-web-guide 0.1 文档》

分享书籍writing idiomatic python ebook

《Python 3 Patterns, Recipes and Idioms》

《Effective Python》

《编写高质量代码:改善Python程序的91个建议》

知乎—Python 有哪些优雅的代码实现让自己的代码更pythonic

写在结尾:

其实,这是一个引流帖,个人技术博客网址请访问 BYA’s Blog 或直接搜索框输入 http://bya.cool
里面目前主要分享一些关于Python基础&进阶、Linux、golang、echarts可视化、主题阅读等 笔记总结,欢迎评论留言~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值