python 编程技巧
1.元组命名
如何为元组中的每个元素命名,提高程序可读性
案例:学生信息系统中数据为固定格式:(名字,年龄,性别,邮箱地址,......)
学生数量很大为了减小存储开销,对每个学生信息用元组表示,但访问时,我们使用索引(index)访问,大量索引降低程序可读性,如何解决这个问题?
student = ('jim',15,'male','jim8789@gmail.com')
# 我们按索引访问
# nanme
print(student[0])
# age
print(student[1])
# ------------第一种方案 分别用变量管理---------------
name =0
age = 1
sex = 2
# 就可以改为
print(student[name])
# -------------第二种方案 --------------
from collections import namedtuple
# 创建一个元组对象
student = namedtuple('Student',['name','age','sex','email'])
s = student('beck',20,'male','beck4654@gmail.com')
print(type(s))
print(s.name)
2.统计序列中元素的出现频度
1、某随机序列[12,5,6,4,6,5,5,7,.....]中,找到出现次数最高的3个元素,它们出现次数是多少?
from random import randint
# 定义一个随机序列
data =[randint(0,20) for i in range(30)]
# 我们以 要统计的数为键, 出现频率数为值 生成一个字典,
# 因为字典key是不能重复的,也进行了除重分组效果
# 先创建一个初始字典
c = dict.fromkeys(data,0)
# 然后对这个序列进行迭代,遇到同样值时候把字典的值进行+1
for x in data:
c[x] +=1
print(c)
# ------- 第二种
from collections import Counter
# 传入需要统计的序列,返回Counter对象元素频度字典
c2 = Counter(data)
# 可以使用most_common(n)方法得到频度最高的n个元素的列表
# 如出现频率最高的前三位
c3=c2.most_common(3)
print(c3)
2、对某英文文章的单词,进行词频统计,找到出现次数最高的10个单词,他们出现次数是多少?
from collections import Counter
import re
# 先打开读出这个文件为一个大字符串
txt = open('file_name').read()
# 用正则 非字母分割,然后在用Counter 构造为Counter对象元素频度字典
c4 =Counter(re.split('\W+',txt))
# 在调用most_common(n)方法得到频度最高的10个元素
count_10=c4.most_common(10)
3.如何根据字典值的大小,对字典中的项排序
字典的元素是成键值对出现的,直接对字典使用sorted() 排序,它是根据字典的键的ASCII编码顺序进行排序,要想让字典根据值的大小来排序,可以有两种方法来实现:
1、利用zip函数将字典数据转化为元组再用sorted() 排序
from random import randint
2 # 用随机函数生成待排序的字典数据
3 my_dict = {x: randint(60, 100) for x in 'abcxyzgkj'}
4 # 将字典数据转化为元组,把字典的值作为元组的第0项,键作为元组的第1项
5 my_tuple = zip(my_dict.values(), my_dict.keys())
6 # 打印输出排序后的结果
7 print(sorted(my_tuple))
2、传递sorted函数的key参数指定为字典的值
sorted函数的格式:sorted(iterable,key,reverse),sorted有iterable,key,reverse三个参数。
iterable 表示可以迭代的对象,例如可以是dict.items()、dict.keys()等。
key 是一个函数,通常使用使用lambda匿名函数来实现,用来选取参与比较的元素。
reverse 用来指定按倒序还是顺序排序,reverse=True是倒序,reverse=False是顺序,默认reverse=False。
from random import randint
2 # 用随机函数生成待排序的字典数据
3 my_dict = {x: randint(60, 100) for x in 'abcxyzgkj'}
4 # 把my_dict.items()所得列表中每个元组的第二个元素(value)传到lambda函数进行排序
5 result = sorted(my_dict.items(), key=lambda x: x[1]) # x[0]是字典的键,x[1]是字典的值
6 # 打印输出排序后的结果
7 print(result)
第一种方法是对字典中键值的全面比较,先比较值的大小,如果两者相等会接着比较键的大小来排序;第二种方法只比较指定的值的大小,如果两者相等则不会比较键的大小,只依照顺序来排序。
4.如何快速找到多个字典中的公共键(key)
from random import randint, sample
# 随机取样进球球员信息
print(sample('abcdef', randint(3, 6)))
# 字典解析产生每轮数据
s1 = {x: randint(1, 4) for x in sample('abcdef', randint(3, 6))}
s2 = {x: randint(1, 4) for x in sample('abcdef', randint(3, 6))}
s3 = {x: randint(1, 4) for x in sample('abcdef', randint(3, 6))}
print(s1, s2, s3)
# 方法1:
# 迭代第1轮中键,之后再去判断这个key是否在s2和s3当中,如果在就表示这个键是公共键
res = []
for k in s1:
if k in s2 and k in s3:
res.append(k)
print(res)
# 方法2:
# 获取每一个字典中的所有key,python2为viewkeys()
print(s1.keys(), s2.keys(), s3.keys())
# 取所有集合的&交集,就是公共键
print(s1.keys() & s2.keys() & s3.keys())
# 方法3:
# 使用map得到每一轮的keys集合
print(list(map(dict.keys, [s1, s2, s3])))
from functools import reduce
# 使用reduce函数,取每一轮的keys集合的交集
print(reduce(lambda a, b: a & b, map(dict.keys, [s1, s2, s3])))
5.如何让字典保持有序
实际案例:
某编程竞赛系统,对参赛选手编程解题进行计时,选手完成题目后,把该选手解题用时记录到字典中,以便赛后按选手名查询成绩。(答题用时越短,成绩越优秀。)
如:LiLei第2名用时43分钟,HanMeimei第5名用时52分钟,Jim第1名用时39分钟
{'LiLei': (2, 43), 'HanMeimei': (5, 52), 'Jim': (1, 39), ...}
比赛结束后,需要按排名顺序依次打印选手成绩,如何实现?
注:为什么不用列表而用字典?就是为了方便赛后可以按名字查询成绩。
Python V3.6版本之前字典无序,3.6版本之后字典开始有序。
解决方案:
- 使用
collections.OrderedDict
(有序字典) - 以
OrderedDict
代替内置字典Dict,依次将选手成绩存入OrderDict
(1)OrderedDict有序字典简单使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
d = dict () print (d) d[ 'Jim' ] = ( 1 , 35 ) d[ 'Leo' ] = ( 2 , 37 ) d[ 'Bob' ] = ( 3 , 40 ) print (d) # 希望迭代字典时候,按每项先后进入顺序打印 for k in d: print (k) # 导入有序字典 from collections import OrderedDict d2 = OrderedDict() d[ 'Jim' ] = ( 1 , 35 ) d[ 'Leo' ] = ( 2 , 37 ) d[ 'Bob' ] = ( 3 , 40 ) for k in d: print (k) |
(2)模拟编写竞赛答题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
# 编程模拟选手 players = list ( 'ABCDEF' ) # 模拟选手的答题时间 from time import time from random import randint from collections import OrderedDict d = OrderedDict() start = time() for i in range ( 6 ): # 等待用户输入,作为阻断进程 input () # 每次随机选择一名选手答题完毕 p = players.pop(randint( 0 , 5 - i)) end = time() print (i + 1 , p, end - start) # 记录成绩 d[p] = (i + 1 , end - start) print () print ( '-' * 20 ) # 按先后进入字典顺序,打印成绩单 for k in d: print (k, d[k]) |
6.历史记录
如何实现用户的历史记录功能(最多n条)
实际案例:
很多应用程序都有浏览用户的历史记录的功能,
例如:
浏览器可以查看最近访问过的网页;
视频播放器可以查看最近播放过视频文件;
Shell可以查看用户输入过的命名;
... ...
现在我们制作了一个简单的猜数字的小游戏,添加历史记录功能,显示用户最近猜过的数字,如何实现?
注:历史记录不能是无限条需要加限定。只显示最近5次的历史记录,其它的抛弃掉。
解决方案:
使用容量为n的队列存储历史记录
使用标准库collections中的deque,它是一个双端循环队列。
程序退出前,可以使用pickle将队列对象存入文件,再次运行程序时将其导入。
代码演示如下:
(1)deque双端队列简单使用
1
2
3
4
5
6
7
8
9
10
11
|
from collections import deque # 创建带有容量的队列 q = deque([], 5 ) # 一次添加多个元素 a = [ 1 , 2 , 3 , 4 , 5 ] q.extend(a) print (q) # 添加第6个元素,查看队列时发现第1个元素已经被挤出去了 q.append( 6 ) print (q) |
(2)pickle保存对象到文件中或读取文件中对象
1
2
3
4
5
6
|
q = deque([ 1 , 2 , 3 , 4 , 5 ], maxlen = 5 ) # 存储对象到文件 pickle.dump(q, open ( 'history' , 'wb' )) # 读取文件中对象 q2 = pickle.load( open ( 'history' , 'rb' )) print (q2) |
(3)实现猜数字游戏的历史记录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
from random import randint from collections import deque import pickle # 猜数字游戏,首先产生一个0到100数字,然后让用户猜 N = randint( 0 , 100 ) print ( '答案:' + str (N)) # 初始化队列,容量为5 history = deque([], 5 ) # 读取文件中的历史记录 history = pickle.load( open ( 'history' , 'rb' )) print (history) def guess(k): if k = = N: print ( 'right' ) return True if k < N: print ( '%s is less-than N' % k) else : print ( '%s is greater-than N' % k) return False while True : line = input ( "Please input a number: " ) if line.isdigit(): k = int (line) # 记录用户输入数字 history.append(k) if guess(k): break elif line = = 'history' or line = = 'h?' : # 用户可以输入命令查看历史记录 print ( list (history)) # 将历史记录保存到文件中 pickle.dump(history, open ( 'history' , 'wb' )) |