对于 Python 新手来说, 写代码很少考虑代码的效率和简洁性, 因此容易造成代码冗长, 执行慢, 这些都是需要改进的地方. 本文是想通过几个案列给新手一点启发, 怎样写 python 代码更优雅.
新人躺坑之一: 不喜欢使用高级数据结构
sets(集合)
很多新手忽视 sets(集合)和 tuple(元组)的强大之处
例如, 取两个列表交集:
- def common_elements(list1, list2):
- common = []
- for item1 in list1:
- if item1 in list2:
- common.append( item1 ) ,
- return common
这样写会更好:
- def common_elements(list1, list2):
- common = set(list1).intersection(set(list2))
- return list(common)
- dic(字典)
新手枚举 (访问和取出) 字典的键和对应值, 认为对应值必须通过键来访问, 往往会这样做:
- my_dict = {'a':1,'b':2}
- for key in my_dict:
- print(key, my_dict[key])
有一个更优雅的方法可以实现:
- my_dict = {'a':1,'b':2}
- for key, value in my_dict.items():
- print(key, value)
对大部分项目来说, 这样写会更加有效率.
tuple(元组)
元组一旦创建就无法更改元素, 看似没有什么用处, 其实元组的作用大着呢! 很多函数方法都会返回元组, 比如 enumerate()和 dict.items(), 并且可以在函数中使用元组, 返回多个值. 还能够很方便地从元组中提取信息:
a,b = ('cat','dog')
上面元组中有两个元素, 分别被赋给 a,b. 如果有多个值, 同样可以提取:
- a,b,c = ('cat','dog','tiger')
- print(a,b,c)
提取首, 尾两个元素:
- first,*_,end = (1,2,3,4,5,6)
- print(first,end)
- # 输出: 1,6
提取首, 中, 尾三部分:
- first,*middle,end = (1,2,3,4,5,6)
- print(first,middle,end)
- # 输出: 1,[2, 3, 4, 5],6
元组还可以用来交换变量:
(a,b,c) = (c,a,b)
上面 a 变成之前的 c,b 变成之前的 a,c 变成之前的 b
元组也能作为字典的键, 所以如果你需要存储数据, 可以使用带有元组键的字典, 比如说经纬度数据.
新人躺坑之二: 不喜欢使用上下文管理器
新手可能会习惯这样进行读取文件操作:
- if os.path.exists(data_file_path):
- data_file = open(data_file_path,'r')
- else:
- raise OSERROR
- print( data_file.read())
- data.close()
这样写会有几个明显的问题:
可能出现文件存在, 但文件被占用, 无法读取的情况
可能出现文件可以被读取, 但操作文件对象出现报错的情况
可能出现忘记关闭文件的情况
如果使用 with... 语句, 问题就迎刃而解了:
- with open(data_file_path,'r') as data_file:
- print(data_file.read)
这样可以捕获任何打开文件或处理数据时的异常情况, 并且在任务处理完后自动关闭文件.
python 初学者可能不太了解上下文管理器的神奇之处, 它真的能带来巨大的便利.
更多关于 python 文件读写和上下文管理器的使用, 可以看下面的文章
一文搞懂 Python 文件读写
一文搞懂 python 错误和异常
新人躺坑之三: 不喜欢使用标准库
标准库 itertools 和 collections 仍然很少被初学者使用
itertools
如果你看到下面的任务:
- list1 = range(1,10)
- list2 = range(10,20)
- for item1 in list1:
- for item2 in list1:
- print(item1*item2)
这是一个嵌套循环操作, 为提高代码效率, 完全可以用 product()函数替代嵌套循环:
- from itertools import product
- list1 = range(1,10)
- list2 = range(10,20)
- for item1,item2 in product(list1, list2):
- print(item1*item2)
这两段代码的结果完全一样, 但使用标准库函数明显更加简洁高效. itertools 还有很多方便操作迭代对象的函数, 比如:
count()函数会创建一个无限迭代器
cycle()函数会把传入的序列无限重复下去
chain()可以把多个迭代对象串联起来
group()函数可以把迭代其中相邻的重复元素挑出来, 放在一起
......
有兴趣可以详细看看 itertools 库的各种神奇函数
collections
新手对 python 集合模块了解的可能并不多, 你可能会遇到这样的情形:
- consolidated_list = [('a',1),('b',2),('c',3),('b',4)]
- items_by_id = {}
- for id_, item in consolidated_list:
- if id_ not in items_by_id:
- items_by_id[id_] = []
- if id_ in items_by_id:
- items_by_id[id_].append(item)
上面代码构建了一个字典, 依次向字典中添加信息, 如果某个键已经存在, 则以某种方式修改该键的值; 如果某个键不存在, 则添加对应键值对.
这种算法非常常见, 你可以用 collects 模块的 defaultdict()函数来实现同样效果:
- from collections import defaultdict
- items_by_id = defaultdict(list)
- consolidated_list = [('a',1),('b',2),('c',3),('b',4)]
- for id_, item in consolidated_list:
- items_by_id[id_].append(item)
在此列中, defaultdict()接受一个 list 作为参数, 当键不存在时, 则返回一个空列表作为对应值.
有时候我们会遇到统计词频的案例, 比如:
- # 统计词频
- colors = ['red', 'blue', 'red', 'green', 'blue', 'blue']
- result = {}
- for color in colors:
- if result.get(color)==None:
- result[color]=1
- else:
- result[color]+=1
- print (result)
- # 输出 {'red': 2, 'blue': 3, 'green': 1}
完全可以用 defaultdict()函数实现上面的计数功能:
- colors = ['red', 'blue', 'red', 'green', 'blue', 'blue']
- d = defaultdict(int)
- for color in colors:
- d[color] += 1
- print(d)
更简单的方法用 collections 模块的 Counter()函数:
- from collections import Counter
- colors = ['red', 'blue', 'red', 'green', 'blue', 'blue']
- c = Counter(colors)
- print (dict(c))
对于备份文件, 新人往往会用 system 模块:
- from os import system
- system("xcopy e:\\sample.CSV e:\\newfile\\")
其实 shutil 模块更好用:
- import shutil
- shutil.copyfile('E:\\q.csv', 'e:\\movie\\q.csv')
因为 shutil 会很详细地报告错误和异常.
新人躺坑之四: 不喜欢使用异常处理
无论老手新手都应该在写代码的时候进行异常处理操作, 这样可以使代码更加健壮. 异常处理一般会用 try...except 语句, 具体使用方法可见:
一文搞懂 python 错误和异常
新人躺坑之五: 不喜欢使用生成器
除非你的 list 十分复杂, 并且频繁调用, 否则都建议使用生成器, 因为它非常节省内存, 举个例子:
- def powers_of_two(max=20000):
- i = 0
- powers = []
- while 2**i < max:
- powers.append[2**i]
- i += 1
- return powers
对于使用次数少, 占据大量内存, 且容易生成的数据, 可以用生成器替代列表存储:
- from itertools import count, takewhile
- def powers_of_two(max=20000):
- for index in takewhile(lambda i: 2**i < max, count(start=0)):
- yield 2**index
更多关于生成器的内容, 请见:
一文搞懂 python 迭代器和生成器
来源: http://www.bubuko.com/infodetail-3255236.html