Python的简单练习
两数的最大公约数
def gcd(a, b):while b != 0:a, b = b, a % breturn a# 示例
a = 36
b = 60
print(f"{a} 和 {b} 的最大公约数是: {gcd(a, b)}")
while b != 0:
-
while
:是 Python 的 循环语句,意思是“当...的时候一直重复做某事”。 -
b != 0
:表示“只要 b 不等于 0”,就继续执行下面的代码。
对角线相连的菱形
n = int(input("请输入菱形的边长:"))# 上半部分(含中间行)
for i in range(n):for j in range(2 * n - 1):if j == n - 1 - i or j == n - 1 + i:print("*", end="")else:print(" ", end="")print()# 下半部分(不含中间行)
for i in range(n - 2, -1, -1):for j in range(2 * n - 1):if j == n - 1 - i or j == n - 1 + i:print("*", end="")else:print(" ", end="")print()
if j == n - 1 - i or j == n - 1 + i
print()直接换行
杨辉三角
def generate_yanghui_triangle(n):triangle = [] # 存储整个三角形for i in range(n):row = [1] * (i + 1) # 每一行最开始全是 1# 从第二个元素到倒数第二个元素开始计算for j in range(1, i):row[j] = triangle[i - 1][j - 1] + triangle[i - 1][j]triangle.append(row)return triangle# 显示杨辉三角
def print_triangle(triangle):n = len(triangle)for i, row in enumerate(triangle):print(" " * (n - i), end="") # 打印前导空格对齐for num in row:print(f"{num} ", end="")print()# 示例
rows = int(input("请输入杨辉三角的行数:"))
triangle = generate_yanghui_triangle(rows)
print_triangle(triangle)
triangle
实际上是一个:列表的列表
[
[1],
[1, 1],
[1, 2, 1],
[1, 3, 3, 1],
...
]
Python 不会主动去判断变量类型,也不要求变量的结构一定一致
只是遍历 triangle
这个变量。只要这个变量“像个列表”,能被遍历就行
len(triangle)
是获取 triangle 的行数
for i, row in enumerate(triangle):一边遍历列表,一边记录当前的“行号” i 和当前的“行内容” row
print(" " * (n - i), end="")让数字靠近中轴线
def func():
print("hello")
这个会报错,因为没有缩进。
def func():
print("hello", end="") # 不换行
print("world")
这个没问题,虽然不换行,但语法结构没错,因为语句都在 def 下面、缩进对齐。
统计不同字符(字母、数字、空格、其他字符)的个数
text = input("请输入一段文本:")letters = 0
digits = 0
spaces = 0
others = 0for ch in text:if ch.isalpha(): # 字母letters += 1elif ch.isdigit(): # 数字digits += 1elif ch.isspace(): # 空格spaces += 1else: # 其他字符others += 1print(f"字母: {letters} 个")
print(f"数字: {digits} 个")
print(f"空格: {spaces} 个")
print(f"其他字符: {others} 个")
检查字符串包含
text = "Life is short.I use python"if "python" in text:new_text = text.replace("python", "Python")print("替换后的字符串:", new_text)
else:print("原字符串:", text)
随机生成六位验证码
random模块
---randint(0,9)可生成一个0-9之间的随机整数
---random.choice()从参数中选择一个
string模块
---string.ascii_letters可得到所有字母
---string.digits可得到所有数字
import random
import stringdef generate_code(length=6):chars = string.ascii_letters + string.digits # 所有字母 + 数字code = ''.join(random.choice(chars) for _ in range(length))return code# 示例
print("生成的验证码是:", generate_code())
random.choice(chars) for _ in range(length),
生成器表达式(generator expression)
''.join(...)
会把生成器里的字符连成一个字符串
code = ''
for _ in range(6):
code += random.choice(chars)也可以但是 .join() + 生成器写法更快、更优雅。
进度条
进度条一般以图形的方式显示已完成任务量和未完成任务量,并以动态文字的方式显示任务的完成度。要求编写程序实现文本进度条功能。
import timedef progress_bar(total=30):for i in range(total + 1):percent = int((i / total) * 100)bar = '#' * i + '-' * (total - i)print(f"\r[{bar}] {percent}%", end="")time.sleep(0.1) # 模拟加载过程print("\n任务完成!")# 示例
progress_bar()
total
表示 进度条的总长度,
i / total
→ 得到当前进度(比如 0.5),* 100
→ 换算成百分比
\r
→ 回到行首,刷新当前行,end=""
避免换行,sleep()
控制速度
过滤敏感词
编写代码,实现具有过滤敏感词功能的程序。
def filter_sensitive(text, sensitive_words):for word in sensitive_words:if word in text:text = text.replace(word, "*" * len(word))return text# 示例
sensitive_list = ["暴力", "不健康", "sb", "傻瓜"]
user_input = input("请输入一段话:")filtered = filter_sensitive(user_input, sensitive_list)
print("过滤后的结果:", filtered)
将字符串的每一个字符放入列表中
text = "hello"
char_list = list(text)
print(char_list)
列表去重
li_one = [1, 2, 1, 2, 3, 5, 4, 3, 5, 7, 4, 7, 8]# 使用集合去重,再转回列表(注意顺序会改变)
li_one_unique = list(set(li_one))print("去重后的列表:", li_one_unique)
set(li_one)
:
-
set
是 Python 中的集合类型,它的特点是:-
不允许重复元素
-
元素无序
-
list(...)
:
-
因为集合类型
set
不是列表,如果你想继续像操作列表那样使用它(比如排序、索引等),就需要转回列表类型。 -
所以用
list(set(li_one))
就把“去重后的集合”变成了一个新列表。
由于集合 set
是无序的,所以转换之后的新列表 li_one_unique
的元素顺序通常会和原来 li_one
中的顺序不一致。
列表合并降序排列
li_num1 = [5, 5, 2, 7]
li_num2 = [3, 6]# 合并
merged_list = li_num1 + li_num2# 降序排序
sorted_desc = sorted(merged_list, reverse=True)print("合并后并降序排序的列表:", sorted_desc)
sorted()
是 Python 的一个内置函数,用于对任何可迭代对象进行排序(比如列表、元组、集合等)。
返回的是一个新的已排序列表,不会修改原来的 merged_list
。
-
reverse
是sorted()
的一个可选参数。 -
当你设置
reverse=True
时,表示按照降序来排列元素。 -
如果是默认的
reverse=False
,就是升序排列。
8名教师随机分配办公室
import random# 老师名单
teachers = ['孙老师', '吴老师', '王老师', '钱老师', '李老师', '周老师', '赵老师', '郑老师']# 办公室,初始化为空列表
offices = [[], [], []]# 打乱老师顺序(确保分配随机性)
random.shuffle(teachers)# 分配老师:前3个给办公室1,接着3个给办公室2,剩下2个给办公室3
offices[0] = teachers[:3]
offices[1] = teachers[3:6]
offices[2] = teachers[6:]# 打印分配结果
for i, office in enumerate(offices, 1):print(f"办公室{i}的人数是{len(office)}. 老师分别是:{', '.join(office)}")
enumerate(offices, 1)
会遍历每一个办公室列表,并同时给它一个“编号”:
第一次循环 | i = 1 , office = ['孙老师', '吴老师', '王老师'] |
---|---|
第二次循环 | i = 2 , office = ['钱老师', '李老师', '周老师'] |
第三次循环 | i = 3 , office = ['赵老师', '郑老师'] |
enumerate(..., 1)
的 1
是指定从1开始编号(默认是从0开始的)。
len(office)
就是这个办公室里老师的数量
join()
是一个字符串方法,用来把一个列表里的字符串连接成一个字符串,中间用逗号隔开。
office = ['孙老师', '吴老师', '王老师']
', '.join(office) → '孙老师, 吴老师, 王老师'
十大歌手评选
votes = {} # 用于记录每个歌手的得票数print("请输入你要投票的歌手名字(输入 'end' 结束):")while True:name = input("投票给:")if name.lower() == 'end':breakvotes[name] = votes.get(name, 0) + 1# 排序输出:按票数从高到低
sorted_votes = sorted(votes.items(), key=lambda x: x[1], reverse=True)print("\n投票结果:")
for singer, count in sorted_votes:print(f"{singer}: {count}票")
votes[name] = votes.get(name, 0) + 1
作用:每投一次票,票数加1。
这行是给歌手(或候选人)计票用的。
-
votes
是一个字典,记录每个人的票数:
例如:{'张三': 2, '李四': 3}
-
votes.get(name, 0)
的意思是:-
去字典里找名字为
name
的那个人的票数; -
如果还没出现过(字典里没有这个名字),就返回
0
; -
相当于默认票数是0。
-
-
然后
+1
:当前票数加一。 -
最终更新写入字典:
-
如果是新的人,就新加进去;
-
如果已经有了,就在原来的基础上加1。
-
sorted_votes = sorted(votes.items(), key=lambda x: x[1], reverse=True)
作用:把投票结果按票数从高到低排序。
-
votes.items()
:把字典转换成一个列表,每一项是(名字, 票数)
这样的元组:{'张三': 3, '李四': 1}.items() → [('张三', 3), ('李四', 1)]
-
sorted(..., key=lambda x: x[1])
:
排序的时候按照元组的第2个元素(也就是票数)来比较。lambda x: x[1]
是匿名函数,意思是“拿到每个(名字, 票数)
元组的票数
”。 -
reverse=True
:表示降序排列(票数多的排前面)。
分类统计字符个数
编写程序,用户输入一个字符串,以回车结束,利用字典统计其中字母和数字出现的次数(回车符代表结束)。
输入格式是一个以回车结束的字符串,例如输入abc1ab,输出{'a': 2, 'b': 2, 'c': 1, '1': 1}。
text = input("请输入一个字符串(回车结束):")
counter = {}for char in text:if char.isalnum(): # 判断是否是字母或数字counter[char] = counter.get(char, 0) + 1print(counter)
计票机制(类歌手)
candidates = ['张三', '李四', '王五']
votes = dict.fromkeys(candidates, 0)print("候选人有:", ', '.join(candidates))
print("请输入投票人名(输入 'end' 结束):")while True:name = input("投票给:")if name.lower() == 'end':breakif name in votes:votes[name] += 1else:print("无效候选人,票数不计。")# 输出最终结果
sorted_votes = sorted(votes.items(), key=lambda x: x[1], reverse=True)print("\n计票结果:")
for person, count in sorted_votes:print(f"{person}: {count}票")
votes = dict.fromkeys(candidates, 0)
作用:根据候选人列表创建一个初始“投票字典”,每个人的票数都设为 0。
candidates = ['张三', '李四', '王五']
votes = dict.fromkeys(candidates, 0) # 得到
votes = {'张三': 0, '李四': 0, '王五': 0}
name.lower()
作用:把用户输入的名字全部转成小写,通常用于不区分大小写的匹配判断。
sorted_votes = sorted(votes.items(), key=lambda x: x[1], reverse=True)
这就是你前面问过的:
-
按照**票数(x[1])**进行排序;
-
reverse=True
表示 降序(票数多的排在前面); -
结果是一个列表,元素是元组
(名字, 票数)
。
斗地主发牌看牌
(要求看牌时排序展示)
import random # 导入随机模块,用于洗牌# 定义花色(suits)和点数(ranks)
suits = ['♠', '♥', '♣', '♦'] # 黑桃、红桃、梅花、方块
ranks = ['3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A', '2'] # 常规牌面# 生成一副完整的扑克牌(不包括大小王的52张 + 小王 + 大王)
deck = [s + r for r in ranks for s in suits] + ['小王', '大王']# 洗牌:打乱deck中的顺序
random.shuffle(deck)# 创建三个玩家的牌堆 + 1个底牌堆
player1 = []
player2 = []
player3 = []
bottom = []# 发牌(共54张,前51张发给三位玩家,最后3张作为底牌)
for i in range(len(deck)):if i < 51:if i % 3 == 0:player1.append(deck[i]) # 玩家1每隔3张拿一张elif i % 3 == 1:player2.append(deck[i]) # 玩家2每隔3张拿一张else:player3.append(deck[i]) # 玩家3每隔3张拿一张else:bottom.append(deck[i]) # 剩下3张作为底牌# 定义一个排序函数:将玩家手牌按点数大小排序
def sort_cards(cards):# 创建一个牌面优先级映射(数字越大表示牌越大)order = {r: i for i, r in enumerate(ranks)} # 3最小,2最大(不含王)order.update({'小王': 13.5, '大王': 14}) # 王的等级高于所有普通牌# 自定义排序函数:提取每张牌的“点数”部分用于比较def card_key(card):if card in ['小王', '大王']:return order[card] # 王直接用其键值return order[card[1:]] # 从第2位开始取(排除花色)# 返回按牌面大小排序后的牌列表return sorted(cards, key=card_key)# 输出发牌结果,并按点数顺序展示每位玩家的手牌
print("\n=== 发牌结果 ===")
print("玩家1:", sort_cards(player1))
print("玩家2:", sort_cards(player2))
print("玩家3:", sort_cards(player3))
print("底牌:", sort_cards(bottom))
deck = [s + r for r in ranks for s in suits]
是花色在前,点数在后的生成方式,比如 ♠3, ♥3, ♣3, ♦3, ♠4, ...
如果你想让点数排在前(比如 3♠),只需调换一下顺序。
for i in range(len(deck)):
deck = ['♠3', '♥4', ..., '小王', '大王']
相对于for i in range(54): # i 依次是 0, 1, 2, ..., 53
-
i < 51
:表示前 51 张是正常发给玩家的; -
i >= 51
:表示最后 3 张是底牌。
然后再通过 i % 3
来轮流分给 3 个玩家。
order = {r: i for i, r in enumerate(ranks)}
这行用的是字典推导式,将点数与大小关系建立起来。
enumerate(ranks) 会返回每个点数及其位置编号:
ranks = ['3', '4', '5', ..., '2']
→ [('3', 0), ('4', 1), ..., ('2', 12)]
所以构造出的字典是:
order = {'3': 0, '4': 1, '5': 2, '6': 3, '7': 4,'8': 5, '9': 6, '10': 7, 'J': 8, 'Q': 9,'K': 10, 'A': 11, '2': 12
}
order.update({'小王': 13.5, '大王': 14})
这行的意思是:往 order 字典中再加两个键值对:比“2”还大,用来确保在排序时,“王”排到最上面。
def card_key(card):
if card in ['小王', '大王']:
return order[card]
return order[card[1:]]
return sorted(cards, key=card_key)
我们之前建立了一个排序规则 order
,用于表示每张牌的大小关系:
order = {'3': 0, '4': 1, ..., '2': 12,'小王': 13.5, '大王': 14
}
现在你有一手牌,比如:
cards = ['♠3', '♦A', '小王', '♥10', '♣2']
def card_key
(card):
定义一个排序时的“取键函数”。
在 Python 的 sorted(..., key=...)
中,我们可以自定义用什么“值”来排序 —— 这里我们自定义的函数名是 card_key
。
if card in ['小王', '大王']: return order[card]
- 如果这张牌是 `'小王'` 或 `'大王'`,那就直接返回 `order` 中对应的数值(13.5 或 14)用于排序。
-
如果不是王,那就说明是正常的扑克牌,比如
'♠3'
、'♥10'
等。 -
card[1:]
表示从索引1开始切取,也就是去掉前面的花色符号,只保留点数:
原始牌 | card[1:] | 排序用值 (order[card[1:]] ) |
---|---|---|
'♠3' | '3' | 0 |
'♦A' | 'A' | 11 |
'♥10' | '10' | 7 |
这样我们就可以用这些数值去比较牌的大小了。
return sorted(cards, key=card_key)
-
sorted(...)
是 Python 内置的排序函数,会返回一个新的列表。 -
key=card_key
指定了“按照什么规则排序”,也就是我们自定义的card_key
函数。 -
这样就能确保牌是按照
order
字典定义的大小顺序排列的。
为什么要用 card[1:]
而不是正则或者其他方式提取点数?
点数部分可能是 '10'
、'J'
、'Q'
,所以不能只取一个字符,要用切片取后面所有字符 → card[1:]
。
编写函数完成角谷猜想
模拟和验证一个著名数学问题——角谷猜想(也叫冰雹猜想,英文叫 Hailstone conjecture 或 Collatz Conjecture)。
对于任意一个正整数 n,重复以下操作:
-
如果 n 是偶数:把 n 变成 n / 2
-
如果 n 是奇数:把 n 变成 3n + 1
重复这个过程,最终总会变成 1
def hailstone_sequence(n):steps = [n] # 记录整个序列(从 n 开始)while n != 1: # 不断重复直到 n 变成 1if n % 2 == 0:n = n // 2 # 偶数除以2else:n = n * 3 + 1 # 奇数乘3加1steps.append(n) # 每次结果加入列表return steps # 返回完整路径
饮品自动售货机
def vending_machine():menu = {'1': ('可乐', 3),'2': ('绿茶', 2.5),'3': ('矿泉水', 2)}print("欢迎使用自动售货机:")for k, v in menu.items():print(f"{k}: {v[0]} - ¥{v[1]}")choice = input("请输入你要购买的饮品编号:")if choice not in menu:print("无效选择")returndrink, price = menu[choice]money = float(input(f"请投币(需要 ¥{price}):"))if money >= price:change = money - priceprint(f"你购买了 {drink},找零 ¥{change:.2f}")else:print("金额不足,交易取消")# 示例调用
vending_machine()
学生管理系统
students = []def add_student(name, age):students.append({'name': name, 'age': age})print(f"添加成功:{name}, 年龄{age}")def show_students():print("当前学生列表:")for s in students:print(f"{s['name']}({s['age']}岁)")# 示例
add_student('小明', 18)
add_student('小红', 17)
show_students()
两个数的最大公约数与最小公倍数
def gcd(a, b):while b:a, b = b, a % breturn adef lcm(a, b):return a * b // gcd(a, b)# 示例
print("最大公约数:", gcd(24, 36))
print("最小公倍数:", lcm(24, 36))
登录验证(次数限制)
def login_system():attempts = 0while attempts < 5:username = input("用户名:")password = input("密码:")if username == 'admin' and password == 'admin123':print("登录成功")returnelse:attempts += 1print(f"请重新登录(还剩 {5 - attempts} 次)")print("账户已被锁定,请联系管理员解锁")login_system()
登录验证装饰器 + 系统操作函数
# 模拟登录状态
login_status = {"logged_in": False}# 登录验证装饰器
def require_login(func):def wrapper(*args, **kwargs):if not login_status["logged_in"]:username = input("用户名:")password = input("密码:")if username == "admin" and password == "admin123":login_status["logged_in"] = Trueprint("✅ 登录成功")else:print("❌ 登录失败,无法操作")returnreturn func(*args, **kwargs)return wrapper# 系统功能函数
@require_login
def add_data():print("数据添加成功")@require_login
def delete_data():print("数据删除成功")@require_login
def update_data():print("数据更新成功")# 测试
add_data() # 第一次需登录
delete_data() # 已登录,无需再输密码
什么是 @require_login
?
Python 的一个语法糖,叫做:函数装饰器(Decorator)
它的作用是:在不修改原函数代码的情况下,为函数增加额外的功能。
@require_login
def add_data():
print("数据添加成功")
等价于:add_data = require_login(add_data)
也就是说,add_data
这个函数被 require_login
装饰后,变成了它返回的 wrapper
函数。
把装饰器 给函数套了个“壳子”:
@xxx
本质上就是:把当前函数交给 xxx()
来加工
def require_login(func):def wrapper(*args, **kwargs):# 做登录验证return func(*args, **kwargs) # 如果验证通过,再运行原函数return wrapper
这段代码的意思其实是:
✨“我定义了一个叫
require_login
的函数工厂,它接受一个函数func
,然后给它包一层登录验证功能,最后返回这个‘增强后的函数’。”✨
第一级函数:require_login(func)
这是 你定义的装饰器函数本体。它接收另一个函数作为参数——就是你想“加功能”的那个函数(比如 add_data()
)。
它的作用就是返回一个新函数:wrapper
。
第二级函数:wrapper(*args, **kwargs)
这是你创建的“壳函数”,负责:
-
先判断登录状态
-
如果未登录就提示并要求输入用户名密码
-
如果登录成功,再执行原函数
func(...)
它就像是在你真正的
add_data()
、delete_data()
等函数 外面套的一层保护壳。
为什么要返回 wrapper
而不是直接运行它?
因为你希望是“以后再用的时候”才执行验证,不是定义的时候就立即执行。
@require_login
def add_data():
...
这时只是把 add_data
换成了新的 wrapper
函数(它内部包含了登录判断 + 原始 add_data),还没有真正执行它。
这段代码是典型的:
“高阶函数 + 闭包结构”
-
高阶函数:函数接收函数作为参数,或返回函数
-
闭包:
wrapper()
内部访问了func
,形成了“带记忆”的函数
写法 | 意义 |
---|---|
*args | 接收任意数量的位置参数(变成一个元组) |
**kwargs | 接收任意数量的关键字参数(变成一个字典) |
用法场景 | 原因 |
---|---|
写装饰器 | 你不知道被包装的函数参数数量和类型 |
写通用函数 | 比如日志函数、统计函数,参数可变 |
接收动态传参 | 比如配置字典、自动调用接口 |
递归求和函数 f(n)
def f(n):if n == 1:return 1return n + f(n - 1)# 示例
print(f(10)) # 输出 55
找出所有既是回文数又是素数的 3 位数
def is_palindrome(n):return str(n) == str(n)[::-1]def is_prime(n):if n < 2:return Falsefor i in range(2, int(n**0.5) + 1):if n % i == 0:return Falsereturn Truedef find_palindromic_primes():result = []for n in range(100, 1000):if is_palindrome(n) and is_prime(n):result.append(n)return resultprint(find_palindromic_primes())
for i in range(2, int(n**0.5) + 1):if n % i == 0:return False
从
2
到√n
(包含)逐一检查是否能整除n
,如果能整除,就不是素数。
**是根号
-
在 Python 中,
**
表示 幂运算(power) -
所以
n**0.5
就等于n 的 0.5 次方
-
而
n 的 0.5 次方
,数学上就是√n
确保从 2
检查到 3
,完整覆盖了素数判断所需范围。
range(2, 3+1) → [2, 3)
range(start, end)
的含义:
参数 | 含义 |
---|---|
start | 起始值(包含) |
end | 终止值(不包含) |
模拟轮盘抽奖函数
import randomdef spin_wheel():r = random.random() # 生成 [0.0, 1.0) 的浮点数if 0 <= r < 0.08:return "🎉 恭喜你抽中一等奖!"elif 0.08 <= r < 0.3:return "🎊 恭喜你抽中二等奖!"else:return "✨ 抽中三等奖,继续加油!"# 测试多次抽奖
for _ in range(5):print(spin_wheel())
保存到你运行脚本时所在的目录下,文件名是你传入的那个 json_path
。
技能类型 | 涉及模块/函数 |
---|---|
文件复制 | shutil.copy() |
字符操作 | .swapcase() |
文件读写 | open(..., "r/w") |
CSV 写入/读取 | csv.writer / csv.DictReader |
JSON 存取 | json.dump() / json.load() |
条件循环与判断 | while 、if |