目录
- 如何让你的代码更有python味?
- 1、三元表达式
- 2、*和**的运用
- 3、列表的使用
- 4、妙用yield和生成器
- 4、巧用context manager
- 5、多使用集合
- 6、判断真伪
- 7、使用操作符in
- 8、使用with
- 8.1 使用with加锁
- 8.2 使用with打开文件
- 8.3 使用 with 忽视异常(仅限Python 3)
- 9、使用join连接字符串
- 10、妙用函数式编程
- max, map, filter, reduce
- 使用zip去迭代而不是多个列表
如何让你的代码更有python味?
大部分编程语言都有共性,也有个性。下手害怕个性,视为异端,抵触之;上手善用个性,欣欣然,妙用之。
1、三元表达式
别抱怨python没有三元表达式,请看:
intro = None
introduction = "haha" if intro == None or len(intro) == 0 else intro
含义隽永,妙味无穷。千言万语,尽在一行中。
2、*和**的运用
定义:一个星号和两个星号分别对list和dict进行packing和unpacking,
请听题:
v, *end = [10, 20, 30]
# gives v= 1, end = [2, 3]
v, *middle, z= [1, 2, 3, 4]
# gives v= 1, middle = [2, 3], z= 4
v, *middle, z= [1, 2, 3, 4]
# gives v= 1, middle = [2, 3]
传可变参数也是用它们:
def add(*args):
sum = 0
for arg in args:
sum += arg
return sum
def say(**kwargs):
for k,v in kwargs.items():
print(f"{k} = {v}")
有了这两个函数,我们可以这样用:
add(1, 2)
add(1, 2, 3)
say(username='user1', passwd='123')
say(username='user1', passwd='123', age=10)
多方便,多神奇啊。
3、列表的使用
列表能运算,能带表达式,能lambda,请听题:
listOfNones = [None] * 6
# gives [None, None, None, None, None, None]
listOfFives = [[5]] *5
# gives [[5], [5], [5], [5], [5]]
filtered_list = [item for item in sequence if item != x]
## to avoid generating a new object, use generators
filtered_list = (item for item in sequence if item != x)
result = list(map(lambda x:x**2, [i for i in range(3)]))
4、妙用yield和生成器
用yield而不是return语句,能改善程序结构,提高执行效率。yield把数据含在嘴里,迭代一次,就往外吐一次数据。
生成器的定义:
- 含有yield的函数叫一个生成器
- 一个函数可以有多个yield语句
- 生成器在迭代时才会做真正的计算,每迭代一次就执行一次
def calculate(size):
result = []
for i in range(size):
result.append(i**2)
return result
for val in calculate(1_000_000):
print(val)
改为:
def calculate(size):
for i in range(size):
yield i**2
for val in calculate(1_000_000):
print(val)
这样更节省内存。
典型的使用案例:scrapy中做网页抓取时,每遇到一个url链接,就yield一把,不断往外"吐"链接,如此循环下去,就形成了深度优先遍历。
4、巧用context manager
Python中,我们通常在两类代码块中分配资源:
- try … finally
- with
例如读大文件的典型写法:
with open("data.txt", "r") as f:
text = f.read()
采用context manager能帮我们管理资源申请和释放:
import contextlib
@contextlib.contextmanager
def db_handler():
try:
stop_db()
yield
finally:
start_db()
with db_handler():
db_backup()
这样等价于:
try:
stop_db()
db_backup()
finally:
start_db()
再举一例,结合with和contextmanager计算某个函数的执行时间:
@contextmanager
def timer(message):
tick = time.time()
yield
tock = time.time()
print("%s: %.3f" % (message, (tock - tick)))
with timer("training"):
do_something()
此处的yield相当于占位符。
5、多使用集合
集合的性能优于函数。如果你不需要许多函数,集合比其他数据结构好。
data = {'find_this', 'among', 'all_the', 'other', 'data'}
if 'find_this' in data:
print('this exists!')
long_stuff = ['this', 'list', 'list', 'is',
'enormous', 'oh', 'my', 'god',
'god', 'what', 'is', 'unique', 'unique']
unique_values = set(long_stuff)
6、判断真伪
##不推荐
if x == True:
# ....
if len(items) != 0:
# ...
if items != []:
# ...
##推荐
if x:
# ....
if items:
# ...
7、使用操作符in
使用 in 更加简洁:
# 字符串包含
if 'hello' in 'helloworld':
# ... do something
# 多次判断
##不推荐
if fruit == "apple" or fruit == "orange" or fruit == "berry":
##推荐
if fruit in ["apple", "orange", "berry"]:
# 字典键值判断
##不推荐
if my_dict.has_key(key):
# ...do something with d[key]
##推荐
if key in my_dict:
# ...do something with d[key]
8、使用with
实现了上下文管理器的类,就可以使用 with 语句。上下文管理器包含两个方法:enter() 和 exit()方法。python还提供了contextmanager 装饰器,更进一步简化了上下文管理器的实现。with相当于try/finally。
8.1 使用with加锁
##不推荐
import threading
lock = threading.Lock()
lock.acquire()
try:
# 互斥操作...
finally:
lock.release()
##推荐
import threading
lock = threading.Lock()
with lock:
# 互斥操作...
8.2 使用with打开文件
##不推荐
f = open("some_file.txt")
try:
data = f.read()
# 其他文件操作..
finally:
f.close()
##推荐
with open("some_file.txt") as f:
data = f.read()
# 其他文件操作...
8.3 使用 with 忽视异常(仅限Python 3)
##不推荐
try:
os.remove("somefile.txt")
except OSError:
pass
##推荐
from contextlib import ignored # Python 3 only
with ignored(OSError):
os.remove("somefile.txt")
9、使用join连接字符串
不推荐:
my_name = 'firstname' + ' ' + 'lastname'
推荐:
my_name = " ".join(['firstname', 'lastname'])
10、妙用函数式编程
max, map, filter, reduce
strs = 'hhhdadamdaaaaaaaaak8888'
max_item = max(strs, key=strs.count) ## 返回出现次数最多的字母
print(max_item)
data = map(lambda x: x ** 2, [1, 2, 3, 4, 5])
pprint(list(data))
max_item = max(迭代对象,lamba x: x对应的计算值)
filter(function, iterable) # 返回由符合条件元素组成的新列表
使用zip去迭代而不是多个列表
students = ['tom', 'dick', 'harry', 'larry', 'tim', 'benny']
scores = [100, 20, 40, 60, 30, 40]
不推荐:
for i in range(len(students)):
print(student[i], scores[i])
推荐:
for student, score in zip(students, scores):
print(student,score)