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'))
posted @ 2022-11-23 22:03  钟鼎山林  阅读(67)  评论(0编辑  收藏  举报