Python大作业

作业1

开发猜数字小游戏。计算机随机生成100以内的数字,让玩家去猜,如果猜的数字 过大成过小都会给出提示,直到猜中该数,显示“恭喜!你猜对了”,同时要统计玩家猜的次数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import random
num = random.randint(1,100)
print("猜数游戏开始!")
print("请输入一个1-100的数字:")
guess = int(input())
count = 1
while guess != num:
if guess > num:
print("猜大了!")
else:
print("猜小了!")
print("请重新输入:")
guess = int(input())
count += 1
print("恭喜!你猜对了!")
print("你一共猜了%d次" % count)

作业2

用字典存储数据,实现一个具有基本功能的通讯录,即具有查询、更新、删除联系人借息等功能,具体功能要求如下。
(1)查询全部联系人信息:显示所有联系人的电话信息。
(2)查询联系人:输入姓名,可以查询当前通讯录中的联系人信息。若联系人存在,则输出联系人信息;若不存在,则输出“联系人不存在”。
(3)插入联系人:可以向通讯录中新建联系人,若联系人已经存在,则询问是否修改联系人信息;若不存在,则新建联系人。
(4)删除联系人:可以删除联系人,若联系人不存在,则告知。

注:需要增加一个年龄这一信息

我的想法

如果将联系人信息写在python文件中,那么每次运行时,上一次修改的数据就无法读取到了。

所以我先将联系人信息字典先存在contacts.json中,每次启动时读取,退出系统时将会保存,下一次会读取到上一次修改后的结果。

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import json
with open('contacts.json', 'r', encoding='utf-8') as file:
contacts_dict = json.load(file)
print('已从 contacts.json 文件中读取到联系人信息。')


# 查询全部联系人信息的函数
def query_all(contacts):
if not contacts:
print('通讯录为空无联系人信息')
else:
for i, (name, info) in enumerate(contacts.items(), start=1):
print("{}. 姓名:{},年龄:{},电话:{}".format(i, name, info['age'], info['phone']))

# 查询单个联系人信息的函数
def query_one(contacts):
name = input('请输入查询的联系人姓名:')
if name in contacts:
info = contacts[name]
print("姓名:{},年龄:{},电话:{}".format(name, info['age'], info['phone']))
else:
print('联系人不存在')

# 更新联系人信息的函数
def update(contacts):
name = input('请输入要修改的联系人姓名:')
if name in contacts:
new_phone = input('请输入新的电话号码:')
new_age = input('请输入新的年龄:')
contacts[name] = {'phone': new_phone, 'age': new_age}
print('修改成功')
else:
print('联系人不存在')

# 删除联系人的函数
def delete(contacts):
name = input('请输入要删除的联系人姓名:')
if name in contacts:
del contacts[name]
print('联系人{}删除成功'.format(name))
else:
print('联系人不存在')

# 新增联系人的函数
def insert_one(contacts):
name = input('请输入要添加的联系人姓名:')
if name in contacts:
print('联系人已存在')
else:
phone = input('请输入电话号码:')
age = input('请输入年龄:')
contacts[name] = {'phone': phone, 'age': age}
print('添加成功')



def menu():
while True:
print("\n---通讯录管理系统---")
print("1 - 查询全部联系人信息")
print("2 - 查询单个联系人信息")
print("3 - 新增联系人信息")
print("4 - 删除联系人信息")
print("5 - 修改联系人信息")
print("6 - 退出通讯录系统")
choice = input("请输入您的选择:")
if choice == '1':
query_all(contacts_dict)
elif choice == '2':
query_one(contacts_dict)
elif choice == '3':
insert_one(contacts_dict)
elif choice == '4':
delete(contacts_dict)
elif choice == '5':
update(contacts_dict)
elif choice == '6':

with open('contacts.json', 'w', encoding='utf-8') as file:
json.dump(contacts_dict, file, ensure_ascii=False, indent=4)
print('联系人信息已保存到 contacts.json 文件中。')
print('感谢使用通讯录系统,再见!')
break

else:
print("输入错误,请重新输入!")


if __name__ == '__main__':
menu()
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
34
{
"张三": {
"phone": "13344445555",
"age": 30
},
"李四": {
"phone": "13888888888",
"age": 40
},
"王五": {
"phone": "13666666688",
"age": 35
},
"赵六": {
"phone": "13143211234",
"age": 28
},
"孙七": {
"phone": "13987654321",
"age": 25
},
"周八": {
"phone": "13212345678",
"age": 22
},
"吴九": {
"phone": "13512345678",
"age": 18
},
"郑十": {
"phone": "13712345678",
"age": 16
}
}

作业三

词频统计,选一篇文章(文本)进行词的统计,打印出top10

我的想法

我选用英文文章,去除标点换行,可以使用re库正则表达式。这次还使用到了pyqt库,因为以前用过,使用还算熟悉。

image-20231125180858794

为了直观看到,也为了方便选择文件,我使用了QT做了一个UI

1
pyuic5 -x demo.ui -o demo.py

使用pyuic5将ui转换成python文件,编写函数

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'form.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets

from collections import Counter
import re
class Ui_WordFreqUI(object):
def setupUi(self, WordFreqUI):
WordFreqUI.setObjectName("WordFreqUI")
WordFreqUI.resize(400, 300)
self.verticalLayout = QtWidgets.QVBoxLayout(WordFreqUI)
self.verticalLayout.setObjectName("verticalLayout")
self.horizontalLayoutTop = QtWidgets.QHBoxLayout()
self.horizontalLayoutTop.setObjectName("horizontalLayoutTop")
self.labelTop = QtWidgets.QLabel(WordFreqUI)
self.labelTop.setObjectName("labelTop")
self.horizontalLayoutTop.addWidget(self.labelTop)
self.word_counts = Counter()
self.comboBox = QtWidgets.QComboBox(WordFreqUI)
self.comboBox.setObjectName("comboBox")
self.comboBox.addItems(["词频统计", "单词统计"])
self.comboBox.currentIndexChanged.connect(self.updateListWidget)
self.horizontalLayoutTop.addWidget(self.comboBox)
self.verticalLayout.addLayout(self.horizontalLayoutTop)
self.listWidget = QtWidgets.QListWidget(WordFreqUI)
self.listWidget.setObjectName("listWidget")
self.verticalLayout.addWidget(self.listWidget)
self.horizontalLayoutBottom = QtWidgets.QHBoxLayout()
self.horizontalLayoutBottom.setObjectName("horizontalLayoutBottom")
self.lineEdit = QtWidgets.QLineEdit(WordFreqUI)
self.lineEdit.setObjectName("lineEdit")
self.horizontalLayoutBottom.addWidget(self.lineEdit)
self.labelBottom = QtWidgets.QLabel(WordFreqUI)
self.labelBottom.setObjectName("labelBottom")
self.horizontalLayoutBottom.addWidget(self.labelBottom)
self.pushButton = QtWidgets.QPushButton(WordFreqUI)
self.pushButton.setObjectName("pushButton")
self.horizontalLayoutBottom.addWidget(self.pushButton)
self.verticalLayout.addLayout(self.horizontalLayoutBottom)
self.fileButton = QtWidgets.QPushButton(WordFreqUI)
self.fileButton.setObjectName("fileButton")
self.fileButton.setText("选择文件")
self.horizontalLayoutTop.addWidget(self.fileButton)
self.retranslateUi(WordFreqUI)
QtCore.QMetaObject.connectSlotsByName(WordFreqUI)

def retranslateUi(self, WordFreqUI):
_translate = QtCore.QCoreApplication.translate
WordFreqUI.setWindowTitle(_translate("WordFreqUI", "词频统计"))
self.labelTop.setText(_translate("WordFreqUI", "Top 10"))
self.labelBottom.setText(_translate("WordFreqUI", "出现次数:"))
self.pushButton.setText(_translate("WordFreqUI", "开始"))

def openFileNameDialog(self):
options = QtWidgets.QFileDialog.Options()
fileName, _ = QtWidgets.QFileDialog.getOpenFileName(None,"选择文本文件", "","Text Files (*.txt);;All Files (*)", options=options)
if fileName:
self.processFile(fileName)

def processFile(self, fileName):
# 打开并读取文件内容
with open(fileName, 'r', encoding='utf-8') as file:
self.text = file.read()

# 进行词频统计
self.word_counts = Counter(re.findall(r'\b\w+\b', self.text.lower()))
self.updateListWidget()



def updateListWidget(self):
sort_option = self.comboBox.currentText()
if sort_option == "词频统计":
# 按词频排序
items = self.word_counts.most_common(10)
else:
# 按字母统计
letter_counts = Counter(re.findall(r'[A-Za-z]', self.text)) # 只考虑字母,并忽略大小写
items = letter_counts.most_common(10) # 取出现频率最高的前10个字母

self.listWidget.clear()
for item, count in items:
self.listWidget.addItem(f'{item.upper()}: {count}')


def search_word_frequency(self):
word_to_search = self.lineEdit.text().lower()
frequency = self.word_counts.get(word_to_search, 0)
self.labelBottom.setText(f'出现次数:{frequency}')
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
WordFreqUI = QtWidgets.QWidget()
ui = Ui_WordFreqUI()
ui.setupUi(WordFreqUI)

ui.fileButton.clicked.connect(ui.openFileNameDialog)
ui.pushButton.clicked.connect(ui.search_word_frequency)

WordFreqUI.show()
sys.exit(app.exec_())

最后,为了方便使用,我使用pyinstaller编译了一下

1
pyinstaller.exe --onefile --windowed demo.py

按钮旁边的输入框,可以输入单词或词组,再次点击按钮可以它的出现次数

image-20231125184156058

image-20231125184332921

作业4

扑克牌发牌程序

我的想法

先找了扑克牌图片,不同花色大小分别命名。这样就可以使用两个列表存花色和大小,然后组合即可。

需要注意的一点是,不能发出一模一样的两张牌,所以可以使用循环先组合出一副扑克牌,这里我使用itertools.product生成一个迭代器,该迭代器生成元组,其中的元素是 rankssuits 中元素的所有可能组合。然后,通过 list() 函数将生成的所有元组放入一个列表中,形成一副完整的扑克牌。

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import tkinter as tk
import random
import itertools
import os
from PIL import Image, ImageTk

def card_sort_key(card):
# 因为A比K大,所以将A的大小设置为13,这样就可以使用数字大小进行排序
rank_order = {'1': 13, '2': 14, '3': 1, '4': 2, '5': 3, '6': 4, '7': 5, '8': 6, '9': 7, '10': 8, '11': 9, '12': 10, '13': 11}
return rank_order[card[0]]

class CardDealingApp:
def __init__(self, master):
self.master = master
master.title("扑克牌发牌")
self.canvas = tk.Canvas(master, width=500, height=600)
self.canvas.pack()

self.deal_button = tk.Button(master, text="发牌", command=self.deal_cards)
self.deal_button.pack()

self.sort_button = tk.Button(master, text="排序牌", command=self.sort_cards)
self.sort_button.pack()

self.deck = self.create_deck() # 创建并洗牌
self.displayed_cards = [] # 已经显示的牌

# 相对位置出了点问题,所以只能使用os库找到脚本绝对位置
current_script_path = os.path.realpath(__file__)
current_script_directory = os.path.dirname(current_script_path)
self.img_folder_path = os.path.join(current_script_directory, 'img')

def create_deck(self):
suits = ['h', 'd', 'a', 's']
ranks = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13']
#生成一个迭代器,该迭代器生成元组,其中的元素是 ranks 和 suits 中元素的所有可能组合。然后,通过 list() 函数将生成的所有元组放入一个列表中,形成一副完整的扑克牌。
deck = list(itertools.product(ranks, suits))
random.shuffle(deck)# 洗牌
print(deck)
return deck



def deal_cards(self):
# 重新创建并洗牌
self.deck = self.create_deck()

# 清空画布上显示的旧牌
self.clear_cards()

# 设置发牌的行数和每行的牌数
rows = 3
cards_per_row = 13

for row in range(rows):
for col in range(cards_per_row):
if len(self.deck) > 0:
card = self.deck.pop()
self.display_card_image(card, row, col) # 这里添加了列索引

def sort_cards(self):
# 将 displayed_cards 分割成每排的牌
rows = [self.displayed_cards[i:i + 13] for i in range(0, len(self.displayed_cards), 13)]

# 对每一排进行排序
sorted_rows = [sorted(row, key=lambda item: card_sort_key(item[2])) for row in rows]

# 将排序后的牌重新组合到 displayed_cards 中
self.displayed_cards = [card for row in sorted_rows for card in row]

# 清空画布并重新显示排序后的牌

for _, image_id, _ in self.displayed_cards:
self.canvas.delete(image_id) # 删除画布上的图片元素
for row_index, row in enumerate(sorted_rows):
for col_index, card_tuple in enumerate(row):
_, _, card = card_tuple
self.display_card_image(card, row_index, col_index)

def display_card_image(self, card, row, col):
file_name = f"{card[1]}{card[0]}.jpg" # 根据牌的花色和数字生成文件名
image_path = os.path.join(self.img_folder_path, file_name)
image = Image.open(image_path)

# 调整图片大小
resized_image = image.resize((100, 150))
photo = ImageTk.PhotoImage(resized_image)

# 计算牌的位置
x_position = 10 + col * 30 # 横向位置
y_position = 50 + row * 160 # 纵向位置

image_id = self.canvas.create_image(x_position, y_position, anchor=tk.NW, image=photo)
self.displayed_cards.append((photo, image_id, card)) # 保存图片对象、图片ID和牌的信息

def clear_cards(self):
for _, image_id, _ in self.displayed_cards:
self.canvas.delete(image_id) # 删除画布上的图片元素
self.displayed_cards.clear() # 清空引用列表



# 创建 Tkinter 窗口
root = tk.Tk()
app = CardDealingApp(root)
root.mainloop()

作业5

image-20231202184821632

image-20231202184828421

image-20231202184834550

image-20231202184841882

1