今日内容大纲介绍
- 扩展: OS模块
- 扩展: 练习题
- 约瑟夫环
- 1234排列组合
- 模拟斗地主-发牌
- 每个字符出现的次数
- 模拟登陆, 只给3次机会
- 扩展-递归
- 扩展-PyMySQL
1.扩展-os模块
"""
os 模块介绍:
概述:
全称叫: Operating System, 系统模块, 主要是操作 文件夹, 文件, 路径等的.
属于第3方的包, 所以我们使用的时候需要导包.
常用函数:
getcwd() 获取当前的工作空间目录(即: 你写相对路径时, 参考的路径). current work directory: 当前工作目录
chdir() 改变工作空间路径. change directory
rmdir() 删除文件夹, 必须是空文件夹. remove directory
mkdir() 制作文件夹. make directory
rename() 改名, 文件名 或者 文件夹名均可.
listdir() 获取指定目录下 所有的子级文件或者文件夹(注意: 不包括子级的子级)
......
"""
# 导包
import os
# 演示 os 模块的函数
# getcwd() 获取当前的工作空间目录(即: 你写相对路径时, 参考的路径). current work directory: 当前工作目录
print(os.getcwd())
# chdir() 改变工作空间路径. change directory
# os.chdir("d:/")
# print(os.getcwd())
# mkdir() 制作文件夹. make directory
# os.mkdir('aa') # 创建aa文件夹, 如果存在就报错, 不存在就创建.
# rmdir() 删除文件夹, 必须是空文件夹. remove directory
# os.rmdir('aa')
# rename() 改名, 文件名 或者 文件夹名均可.
# os.rename('aa', 'bb')
# os.rename('1.txt', 'hg.txt')
# listdir() 获取指定目录下 所有的子级文件或者文件夹(注意: 不包括子级的子级)
# file_list = os.listdir('./')
file_list = os.listdir('d:/')
print(file_list)
# 读取文件数据.
# f = open('1.txt', 'r', encoding='utf-8')
# print(f.read())
# f.close()
2.约瑟夫环
"""
约瑟夫环介绍:
概述:
它也叫幸运数字, 规则是: 假设有一天你穿越到了古代, 碰巧遇到古代的皇帝在杀人, 不巧的是, 你也在此列.
规则是: 让所有的"犯人"围成一个圈, 开始数数字, 只要数到3或者3的倍数, 就干掉这个人, 直至剩下最后一人, 她/他站的位置就是: 幸运数字.
如果可以让你选择自己的站位, 你会站到哪里?
需求:
键盘录入1个数字, 表示"犯人"总数, 打印: 幸运数字即可.
例如:
10个犯人, 幸运数字是: 4
"""
# 1. 键盘录入参与游戏的总人数, 并接收.
n = int(input('请录入参与游戏的总人数: ')) # 假设: 5
# 2. 根据总人数, 生成对应的 编号列表. 即: [1, 2, 3, 4, 5]
num_list = [i for i in range(1, n + 1)]
# print(num_list)
# 3. 核心细节1: 定义两个变量, num表示当前数到的数字, i表示当前这个人的编号(索引)
num, i = 0, 0
# 4. 具体的游戏过程, 循环操作, 直至列表剩下1个元素.
while len(num_list) != 1:
# 数数字.
num += 1
# 5. 核心细节2: 如果一圈都数完了, 重置 索引为 0, 从头继续数, 下一轮了.
if i == len(num_list):
i = 0
# 6. 如果当前数到的数字是3或者3的倍数, 就从列表中删除这个元素.
if num % 3 == 0:
num_list.pop(i)
# 核心细节3: 删除元素后, 列表长度变化了, 索引要 -1
i -= 1
# 7. 当前的人数完后, 下个人开始数数字即可.
i += 1
# 8. 走到这里, 列表只剩下1个元素了, 它就是幸运数字. 打印即可.
print(f'参与游戏总人数为: {n}, 幸运数字为: {num_list[0]}')
3.排列组合
"""
案例:
已知有1, 2, 3, 4四个数字, 问: 它们能组合成的四位数有哪些, 并打印到控制台.
需求:
1. 数字不能重复, 即: 1234, 2134均可, 1122不行. 按照3个一行进行输出.
1234 1243 1324
2143...
2. 在上个需求的基础上, 实现: 数字1和3不能挨着, 即: 1324, 3124不行, 1234可以
3. 在上个需求的基础上, 实现: 数字4不能开头.
4. 扩展要求: 代码总行数不能超过 7 行.
解题思路:
解题思路有很多, 我的这个最简单, int => str, 题目就做出来了.
"""
count = 0 # 计数器
for i in range(1234, 4322):
s = str(i) # 1234 => '1234'
if '1' in s and '2' in s and '3' in s and '4' in s and '13' not in s and '31' not in s and s[0] != '4':
# 走到这里, 是我们要的数据, 计数器 + 1
count += 1
print(i, end='\n' if count % 3 == 0 else '\t')
4.统计每个字符出现的次数
"""
需求:
键盘录入1个字符串, 并接收, 统计其中每个字符的次数, 并将结果打印到控制台上.
"""
# 1. 键盘录入1个字符串,并接收.
s = input('请录入1个字符串, 我来统计每个字符的次数: ') # 假设: aaabbc
# 2. 定义字典, 记录每个字符 及其 次数. 字符做键, 次数做值, 例如: 'a':3, 'b':2, 'A':1
# wc_dict = {} # word count: 单词数量 hello world python sql linux
# 方式1: 分解版
# # 3. 遍历上述的字符串, 获取到每个字符, 充当字典的键.
# for key in s: # i的值: 'a', 'a', 'a', 'b', 'b', 'c'
# # 4. 核心: 判断字典中是否有这个键, 有就将其次数 + 1 重新存储.
# if key in wc_dict:
# # 例如: 'a': 2 => 'a': 3
# wc_dict[key] = wc_dict[key] + 1
# else:
# # 5. 没有说明这个键是第一次出现, 就将其次数记录为1
# # 例如: 'b', 1
# wc_dict[key] = 1
# 方式2: 三元运算符
# 3. 遍历上述的字符串, 获取到每个字符, 充当字典的键.
# for key in s: # i的值: 'a', 'a', 'a', 'b', 'b', 'c'
# wc_dict[key] = wc_dict[key] + 1 if key in wc_dict else 1
# 方式3: 字典推导式
wc_dict = {key: s.count(key) for key in s} # key是字符串中的每个字符.
# 6. 循环结束后, 打印字典即可.
print(wc_dict)
5.模拟登陆
# 需求: 模拟登陆, 只给3次机会.
# 1. 假设初始的账号 和 密码.
username = 'heima'
password = 'ai28'
# 2. 因为只给3次机会, 建议使用 for 循环.
for i in range(3): # i的值: 0, 1, 2
# 3. 提示用户录入账号或者密码并接收.
uname = input('请录入您的账号: ')
pwd = input('请录入您的密码: ')
# 4. 判断是否登录成功, 成功则提示, 然后程序结束.
if uname == username and pwd == password:
print(f'欢迎您, {uname}!') # 可以是昵称, nickname
break # 记得结束循环.
else:
# 5. 不成功, 就判断还有几次登陆机会, 并提示.
# if i == 2:
# print('录入错误次数已达上限, 账号被锁定, 请于管理员联系: 010-123456')
# else:
# print(f'录入有误, 请重新录入, 您还有 {2 - i} 次机会!') # 2, 1, 0
print('录入错误次数已达上限, 账号被锁定, 请于管理员联系: 010-123456' if i == 2 else f'录入有误, 请重新录入, 您还有 {2 - i} 次机会!')
6.模拟斗地主发牌
# 案例: 模拟斗地主发牌.
import random
# 定义变量, 表示扑克牌.
poker_dict = {} # 键: 牌的索引, 值: 具体的牌. 规则: 牌越小, 索引越小.
poker_index = [] # 所有的 牌的索引, 我们发的是这个, 看牌是: 排序后, 根据键找值.
p1 = [] # 玩家1
p2 = [] # 玩家2
p3 = [] # 玩家3
dp = [] # 底牌
# 1. 买牌.
def get_poker():
global poker_dict
# 1.1 定义 花色列表.
color_list = ['♠', '♥', '♦', '♣']
# 1.2 定义 点数列表.
num_list = ['3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A', '2']
# 1.3 生成 字典, 键: 索引, 值: 牌. 规则: 牌越小, 索引越小.
# 列表
poker_list = [color + num for num in num_list for color in color_list]
# 字典
poker_dict = {i: poker_list[i] for i in range(len(poker_list))}
# 添加大小往.
poker_dict[52] = '小🤡'
poker_dict[53] = '大🤡'
# print(poker_dict)
# 2. 洗牌.
def shuffle_poker():
global poker_index
# 获取所有牌的索引.
poker_index = list(poker_dict.keys())
# print(poker_index)
# 具体的洗牌动作.
random.shuffle(poker_index)
# print(poker_index)
# 3. 发牌
def send_poker():
global p1, p2, p3, dp
# 规则: 最后3张做底牌, 其它轮询发送.
for i in range(len(poker_index)): # i就是 打乱顺序后的牌的编号的 索引
# 发送底牌
if i >= len(poker_index) - 3:
dp.append(poker_index[i])
elif i % 3 == 0:
p1.append(poker_index[i])
elif i % 3 == 1:
p2.append(poker_index[i])
else:
p3.append(poker_index[i])
# 4. 看牌.
def look_poker(player_name, player_poker_num):
"""
根据玩家手中 牌的编号, 取 牌盒poker_dict中找 牌.
:param player_name: 玩家名
:param player_poker_num: 玩家手中的牌的编号.
:return:
"""
# 4.1 排序.
player_poker_num.sort()
# 4.2 玩家手中具体的牌.
player_poker = [poker_dict[i] for i in player_poker_num]
# 4.3 打印结果
print(f'{player_name}的牌是: {player_poker}')
# 在main函数中调用.
if __name__ == '__main__':
# 1. 买牌
get_poker()
# 2. 洗牌
shuffle_poker()
# 3. 发牌
send_poker()
# 看牌
look_poker('刘亦菲', p1)
look_poker('赵丽颖', p2)
look_poker('张小二', p3)
look_poker('底牌', dp)
7.递归-求阶乘
"""
递归 介绍:
概述:
递归指的是 函数自己调用自己的情况.
细节:
1. 递归必须要有出口, 否则: 就是死递归, 容易造成 栈内存溢出.
2. 递归不能调用次数过多, 否则: 容易造成 栈内存溢出.
3. 递归必须要有 规律, 即: 重复做的事儿.
4. 总结, 搞定递归很简单, 只要: 分析出 出口 和 规律即可.
经典案例:
1. 求阶乘.
2. 斐波那契数列, 也叫: 不死神兔.
# 需求: 求5的阶乘, 分析流程如下:
5! = 5 * 4 * 3 * 2 * 1 ---
5 * 4! |
4 * 3! 规律
3 * 2! |
2 * 1! ---
1! = 1 出口
总结:
出口: 1! = 1
规律: n! = n * (n - 1)!
"""
# 需求: 求5的阶乘. 5! = 5 * 4 * 3 * 2 * 1
# 1. 定义函数 factorial(n), 计算: n的阶乘.
def factorial(n):
# 出口: 1! = 1
if n == 1:
return 1
# 规律: n! = n * (n - 1)!
return n * factorial(n - 1)
# 2. 调用 factorial()函数.
if __name__ == '__main__':
print(factorial(5))
8.递归-斐波那契数列
"""
需求:
传说在很久以前, 有一个意大利青年叫: 斐波那契, 有一天他提出1个非常有意思的问题:
1. 1对小兔子, 1个月之后会长成1对大兔子.
2. 1对大兔子, 每个月都会生1对小兔子.
3. 假设所有兔子都不死的情况下, 问: 1对小兔子, 1年(即: 12个月)之后, 会变成多少对兔子. 144对.
分析思路:
月份 大兔子对数 小兔子对数 兔子总对数
1月 0 1 1
2月 1 0 1
3月 1 1 2
4月 2 1 3
5月 3 2 5
6月 5 3 8
......
总结:
出口: 前两个月的兔子对数都是 1
规律: 从第3个月开始, 兔子对数 = 上个月的兔子对数 + 上上个月的兔子对数.
"""
# 1. 定义函数, 计算兔子对数.
def get_rabbit(m):
"""
根据传入的月份, 计算兔子对数.
:param m: 月份
:return: 当月的兔子对数.
"""
# 出口: 前两个月的兔子对数都是
# if m == 1 or m == 2:
if m in [1, 2]:
return 1
# 规律: 从第3个月开始, 兔子对数 = 上个月的兔子对数 + 上上个月的兔子对数.
return get_rabbit(m - 1) + get_rabbit(m - 2)
# 2. 调用函数.
if __name__ == '__main__':
print(get_rabbit(12)) # 第12个月, 144对
9.pymysql-入门
"""
pymysql 模块解释:
概述:
它属于第三方的模块, 用之前需要先安装一下. 它是Python操作MySQL数据库的规范和规则.
里边定义了一些API(函数), 可以帮助我们实现通过Python操作MySQL, 进行 增删改查的操作.
安装方式:
方式1: DOS命令方式, pip install pymysql [-i 镜像地址]
例如: 清华大学镜像 https://pypi.tuna.tsinghua.edu.cn/simple
方式2: 导包的时候 安装.
写完包名后, 按下 alt + enter, 给出建议, 选择: install 包名.
pymysql的操作步骤:
1. 获取连接对象. Python连接MySQL的对象.
2. 获取游标对象. 可以执行SQL语句的对象.
3. 执行SQL语句, 获取结果集.
4. 操作结果集.
5. 释放资源.
大白话解释pymysql的步骤:
1. 找到前台小姐姐. 你(Python) 和 黑马(MySQL)建立了连接, 通过: 前台小姐姐(连接对象)
2. 前台小姐姐找到 任课老师. 任课老师: 讲解知识点的.
3. 任课老师给大家(学生)讲课, 获取资料: 视频, 代码, 笔记, 图片, 作业...
4. 你(学生)操作结果集, 视频: 看, 代码: 敲, 笔记: 整理...
5. 跟 任课老师, 前台小姐姐 说再见.
细节:
需要开启MySQL服务, 例如: 小皮.
"""
import pymysql
# 1. 获取连接对象. 6个参数: MySQL所在的主机ip或者主机名, 端口号, 账号, 密码, 库名, 码表
conn = pymysql.connect(
host='localhost',
port=3306,
user='root',
password='123456',
database='day02',
charset='utf8'
)
# 2. 获取游标对象.
cus = conn.cursor()
# 3. 执行SQL语句, 获取结果集.
sql = 'select * from hero;'
cus.execute(sql)
# 4. 操作结果集.
# 场景1: 从游标对象中, 获取所有的数据. 格式为: 元组嵌套元组, ((1, '鸠摩智', 9), (3, '乔峰', 1)...)
# data = cus.fetchall()
# 场景2: 从游标对象中, 获取第1条数据.
# data = cus.fetchone()
# 场景3: 从游标对象中, 获取n条数据.
data = cus.fetchmany(3)
print(data)
# 5. 释放资源.
cus.close()
conn.close()
10.pymysql-curd
# 案例: 演示PyMySQL操作 MySQL数据库, 进行 CURD 增删改查操作.
import pymysql
# 1. pymysql模块 操作 mysql数据库, 增
def insert_method():
# 1. 获取连接对象.
conn = pymysql.connect(host='localhost', port=3306, user='root', password='123456', database='day02',
charset='utf8')
# 2. 根据连接对象, 获取 游标对象.
cur = conn.cursor()
# 3. 执行SQL语句, 获取结果集.
sql = 'insert into hero values(6, "杨过", 20);'
n = cur.execute(sql) # n就是受到影响的行数, 例如: 增了几行, 删了几行, 改了几行.
# 核心操作: 增, 删, 改属于更新语句, 操作之后必须 commit()提交, 才会保存结果.
conn.commit()
# 4. 操作结果集.
# if n > 0:
# print('添加成功!')
# else:
# print('添加失败!')
print('添加成功' if n > 0 else '添加失败!')
# 5. 释放资源.
cur.close()
conn.close()
# 2. pymysql模块 操作 mysql数据库, 删
def delete_method():
# 1. 获取连接对象.
conn = pymysql.connect(host='localhost', port=3306, user='root', password='123456', database='day02',
charset='utf8')
# 2. 根据连接对象, 获取 游标对象.
cur = conn.cursor()
# 3. 执行SQL语句, 获取结果集.
sql = 'delete from hero where hid > 3;'
n = cur.execute(sql) # n就是受到影响的行数, 例如: 增了几行, 删了几行, 改了几行.
# 核心操作: 增, 删, 改属于更新语句, 操作之后必须 commit()提交, 才会保存结果.
conn.commit()
# 4. 操作结果集.
print('删除成功' if n > 0 else '删除失败!')
# 5. 释放资源.
cur.close()
conn.close()
# 3. pymysql模块 操作 mysql数据库, 改
def update_method():
# 1. 获取连接对象.
conn = pymysql.connect(host='localhost', port=3306, user='root', password='123456', database='day02',
charset='utf8')
# 2. 根据连接对象, 获取 游标对象.
cur = conn.cursor()
# 3. 执行SQL语句, 获取结果集.
sql = 'update hero set hname="神雕侠", kongfu_id=100 where hid=6;'
n = cur.execute(sql) # n就是受到影响的行数, 例如: 增了几行, 删了几行, 改了几行.
# 核心操作: 增, 删, 改属于更新语句, 操作之后必须 commit()提交, 才会保存结果.
conn.commit()
# 4. 操作结果集.
print('修改成功' if n > 0 else '修改失败!')
# 5. 释放资源.
cur.close()
conn.close()
# 4. pymysql模块 操作 mysql数据库, 查
def query_method():
# 1. 获取连接对象.
conn = pymysql.connect(host='localhost', port=3306, user='root', password='123456', database='day02', charset='utf8')
# 2. 根据连接对象, 获取 游标对象.
cur = conn.cursor()
# 3. 执行SQL语句, 获取结果集.
sql = 'select * from hero;'
cur.execute(sql)
# 4. 操作结果集.
data = cur.fetchall()
for line in data:
print(line)
# 5. 释放资源.
cur.close()
conn.close()
# 5. 在main方法中, 测试调用:
if __name__ == '__main__':
# 添加 表数据
# insert_method()
# 修改 表数据
# update_method()
# 删除 表数据
delete_method()
# 查看 表数据.
query_method()