Python之 -- 抽奖系统的开发(一)
Hello!大家好!都让开!
是的没错,这次准备手敲一个非常牛批之《老闫真牛批-抽奖系统》
o(* ̄︶ ̄*)o
o(* ̄︶ ̄*)o
其实也么有很牛批哈,装个x!!
o(* ̄︶ ̄*)o
o(* ̄︶ ̄*)o
自从上次写了数字猜猜猜后,就对这种小游戏上瘾了,既好玩,又能巩固知识;
所以呢这次就再写一个小游戏,但是打算写个稍微复杂一点的
思前想后,觉得抽奖系统到时一个不错的选择
好了,圆规正传,开始今天的装x之旅!
首先,先来搭个架子,
好,架子搭好之后,正式开始动工!
首先先初始化一下我们的奖品库json文件和用户库json文件,为什要用json文件呢,是因为这个方便哈,还有就是想练习下文件的读写
第二步,开始写基础操作函数模块base.py
首先,我们先判断一下gift.json和user.json的文件格式,路径
这里可以把判断的函数写到公共函数模块utils.py
1 # 判断文件类型路径 2 def check_file(path): 3 if not os.path.exists(path): # os.path.exists路径存在则返回True,路径损坏返回False 4 raise NotPathError('Not Found path') 5 6 if not path.endswith('.json'): # str.endswith('.json')判断字符串结尾是不是以指定 7 raise FormatError('need json format') 8 9 if not os.path.isfile(path): # os.path.isfile判断路径是否为文件 10 raise NotFileError('this is not a file')
之后在base.py引用这个函数,来验证两个json文件
# coding:utf-8 import osimport json from common.utils import check_file class Base(object): def __init__(self, user_json, gift_json): self.user_json = user_json self.gift_json = gift_json self.__check_user_json() self.__check_gift_json() # 判断user_json文件的类型以及地址 def __check_user_json(self): check_file(path=self.user_json) # 判断gift_json文件的类型以及地址 def __check_gift_json(self): check_file(path=self.gift_json)
由于系统很多地方肯定是会有写入文件的这个操作,所以干脆先写一个写入文件的函数,后面方便一些
# 定义一个写入的函数 def __save(self, data, path): json_data = json.dumps(data) with open(path, 'w') as f: f.write(json_data)
下面就是写入用户函数,我初步的想法是,用户信息包含用户名,权限,是否启用,创建时间,修改时间,抽到的奖品列表
是否启用默认给了True,创建时间和修改时间自动写入,奖品列表初始化为空的
那么只需要传入用户名和权限就可以了
注:下面的抛出异常代码,是我自定义的,后面我会统一贴出来
# 写入user信息 def __write_user(self, **user): # 判断入参是否合规,是否包含username和role if "username" not in user: raise ValueError('missing username') if "role" not in user: raise ValueError('missing role') user['active'] = True user['create_time'] = time.time() user['update_time'] = time.time() user['gifts'] = [] users = self.__read_user() # 如果username已经存在了,那就抛出异常 if user['username'] in users: raise UserExistsError('username: %s had exists' % user['username']) # 如果username不存在,那就写入文件 users.update( {user['username']: user} ) # 转码为json,并写入 self.__save(data=users, path=self.user_json)
既然有写出的操作,那就肯定会有读的操作吧,那就再写一个读取user文件的方法
# 读取user文件,并解码为字典格式 def __read_user(self, time_to_str=False): with open(self.user_json, 'r') as f: data = json.loads(f.read()) # 把文件的时间戳改为字符串格式 if time_to_str is True: for k, v in data.items(): v['create_time'] = timestamp_to_string(v['create_time']) v['update_time'] = timestamp_to_string(v['update_time']) # 这里用的是时间戳转码,函数会在下面写出 data[k] = v return data
由于写入用户信息的时候,创建时间和修改时间是以时间戳的格式写进去的,读出来的时候看着不方便,所以就在公共函数模块,写了一个时间戳转码的函数
utils.py
# 时间戳格式化 def timestamp_to_string(timestamp): time_obj = time.localtime(timestamp) time_str = time.strftime('%Y-%m-%d %H:%M:%S', time_obj) return time_str
让我们再来想想,既然定义了有权限字段,那肯定会有修改权限的操作
那就搞一个修改权限role字段的方法吧
判断role是否符合规范的里的 ROLES 是我在常量模块consts.py里定义了一个列表,固定了两种写法
如果传入的role字段跟列表里的对比不上,那就说明传的不规范
# 修改role字段 def __change_role(self, username, role): users = self.__read_user() user = users.get(username) if not user: return False # 判断入参role是否符合规范 if role not in ROLES: raise RoleError('not use role: %s' % role) user['role'] = role user['update_time'] = time.time() users[username] = user self.__save(data=users, path=self.user_json) return True
既然能修改权限了,状态也得能让人修改吧
# 修改active字段 def __change_active(self, username): users = self.__read_user() user = users.get(username) if not user: return False user['active'] = not user['active'] user['update_time'] = time.time() users[username] = user self.__save(data=users, path=self.user_json) return True
既然能写入用户,那也得能删除用户是不
搞起
# 删除用户 def __delete_user(self, username): users = self.__read_user() user = users.get(username) if not user: return False delete_user = users.pop(username) self.__save(data=users, path=self.user_json) return delete_user
好了,操作用户这一块算是基本搞定,下面开始搞奖品库文件
先来顶一个初始化奖品库结构的文件
def __init_gift(self): # 等级越高,奖品约稀有,每个等级里面又包含几种等级的奖品 data = { 'level1': { 'level1': {}, 'level2': {}, 'level3': {} }, 'level2': { 'level1': {}, 'level2': {}, 'level3': {} }, 'level3': { 'level1': {}, 'level2': {}, 'level3': {} }, 'level4': { 'level1': {}, 'level2': {}, 'level3': {} } } gifts = self.__red_gift() if len(gifts) != 0: return self.__save(data=data, path=self.gift_json)
老样子,在搞一个读取的方法
# 读取奖品文件内容 def __red_gift(self): with open(self.gift_json, 'r') as f: data = json.loads(f.read()) return data
写到后面,发现上面写的那个读取的方法,不够完善,很多地方需要用到对应层级的数据,所以干脆写一个方法
这个方法能获取到对应层级的数据,方便很多
def __check_and_getgift(self, first_level, second_level, gift_name): if first_level not in FIRSTLEVELS: raise LevelError('first level not exists: %s' % first_level) if second_level not in SECONDLEVELS: raise LevelError('second level not exists: %s' % second_level) gifts = self.__red_gift() level_one = gifts[first_level] # 获取level的对象"level1": {"level1": {}, "level2": {}}, "level3": {}} level_two = level_one[second_level] # 获取level2的对象"level2": {} if gift_name not in level_two: return False return { 'level_one': level_one, 'level_two': level_two, 'gifts': gifts }
既然是奖品库,那肯定得有添加奖品的步骤,所以就搞一个添加奖品的方法
这里比较复杂,也是搞了我好久时间
# 添加奖品到gift_json文件 def write_gift(self, first_level, second_level, gift_name, gift_count): if first_level not in FIRSTLEVELS: raise LevelError('first level not exists: %s' % first_level) if second_level not in SECONDLEVELS: raise LevelError('second level not exists: %s' % second_level) gifts = self.__red_gift() current_gift_pool = gifts[first_level] # 获取level的对象"level1": {"level1": {}, "level2": {}}, "level3": {}} current_second_gift_pool = current_gift_pool[second_level] # 获取level2的对象"level2": {} # 如果传入的count小于等于0,那就默认count为1 if gift_count <= 0: gift_count = 1 # 如果添加的奖品已经存在奖品库,那么就把添加的商品库存+1 if gift_name in current_second_gift_pool: current_second_gift_pool[gift_name]['count'] = current_second_gift_pool[gift_name]['count'] + gift_count else: # 如果添加的商品不在奖品库,那就把奖品写入文件 current_second_gift_pool[gift_name] = { 'name': gift_name, 'count': gift_count } # 还原level2的文件内容 current_gift_pool[second_level] = current_second_gift_pool # 还原level1的文件内容 gifts[first_level] = current_gift_pool # 编码为json以及写入json文件 self.__save(data=gifts, path=self.gift_json)
接下来是修改奖品库存的方法
如果传入奖品数量 那就减去传入的数量
如果不传入,那奖品数量就默认减一
这块可能后面要改,因为要验证admin还是普通用户
先这样吧
def __update_gift(self, first_level, second_level, gift_name, gift_count): data = self.__check_and_getgift( first_level=first_level, second_level=second_level, gift_name=gift_name ) if not data: return data current_gift_pool = data.get('level_one') current_second_gift_pool = data.get('level_two') gifts = data.get('gifts') current_gift = current_second_gift_pool[gift_name] if current_gift['count'] - gift_count < 0: raise NegativeNumberError('gift count can not nagative') current_gift['count'] -= gift_count current_second_gift_pool[gift_name] = current_gift current_gift_pool[second_level] = current_second_gift_pool gifts[first_level] = current_gift_pool self.__save(gifts, self.gift_json)
最后,再来定一个删除奖品的方法
def __delete_gift(self, first_level, second_level, gift_name): data = self.__check_and_getgift( first_level=first_level, second_level=second_level, gift_name=gift_name ) if not data: return data current_gift_pool = data.get('level_one') current_second_gift_pool = data.get('level_two') gifts = data.get('gifts') delete_gifts = current_second_gift_pool.pop(gift_name) current_gift_pool[second_level] = current_second_gift_pool gifts[first_level] = current_gift_pool self.__save(gifts, self.gift_json) return delete_gifts
base.py总算搞完了,也是废了不少功夫,下面来测试一下吧
先来试一下创建用户
ok,没有报错,再来看一下user.json
成功写入!
再来试一下修改用户权限
ok!运行成功,看下有没有修改成功
漂亮,没毛病!
再来试一下修改状态,由于状态就两种true和false,
所以定义方法的时候,只要调用,就反方向修改,所以也不用传状态值了,我可真聪明
没毛病,检查一下
成功!老闫666啊!!
好了,继续测试奖品库这一块
先试下初始化,初始化这一块没设置入参,每次执行Base类会自动检查一遍,如果json文件是空的就给初始化
ok!结构也进来了
下面开始添加奖品
哦报错了,检查下为啥子
哦原来是入参count我设定了对比,只有int类型才可以,看来后面要加个校验,修改下入参再试下
okk!修改后没问题了,成功把老闫的臭脚加入奖品库
后面还有几个方法就不一一测试了
主要是写累了,不想写了
好了,本次就先这样了,admin和user模块下次再发,让我好好思考思考!
最后附上本次的代码!
# coding:utf-8 import os import time import json from common.utils import check_file, timestamp_to_string from common.error import (UserExistsError, RoleError, LevelError, NegativeNumberError, CountError) from common.consts import ROLES, FIRSTLEVELS, SECONDLEVELS class Base(object): def __init__(self, user_json, gift_json): self.user_json = user_json self.gift_json = gift_json self.__check_user_json() self.__check_gift_json() self.__init_gift() # 判断user_json文件的类型以及地址 def __check_user_json(self): check_file(path=self.user_json) # 判断gift_json文件的类型以及地址 def __check_gift_json(self): check_file(path=self.gift_json) # 读取user文件,并解码为字典格式 def __read_user(self, time_to_str=False): with open(self.user_json, 'r') as f: data = json.loads(f.read()) # 把文件的时间戳改为字符串格式 if time_to_str is True: for k, v in data.items(): v['create_time'] = timestamp_to_string(v['create_time']) v['update_time'] = timestamp_to_string(v['update_time']) data[k] = v return data # 写入user信息 def __write_user(self, **user): # 判断入参是否合规,是否包含username和role if "username" not in user: raise ValueError('missing username') if "role" not in user: raise ValueError('missing role') user['active'] = True user['create_time'] = time.time() user['update_time'] = time.time() user['gifts'] = [] users = self.__read_user() # 如果username已经存在了,那就抛出异常 if user['username'] in users: raise UserExistsError('username: %s had exists' % user['username']) # 如果username不存在,那就写入文件 users.update( {user['username']: user} ) # 转码为json,并写入 self.__save(data=users, path=self.user_json) # 修改role字段 def __change_role(self, username, role): users = self.__read_user() user = users.get(username) if not user: return False # 判断入参role是否符合规范 if role not in ROLES: raise RoleError('not use role: %s' % role) user['role'] = role user['update_time'] = time.time() users[username] = user self.__save(data=users, path=self.user_json) return True # 修改active字段 def __change_active(self, username): users = self.__read_user() user = users.get(username) if not user: return False user['active'] = not user['active'] user['update_time'] = time.time() users[username] = user self.__save(data=users, path=self.user_json) return True # 删除用户 def __delete_user(self, username): users = self.__read_user() user = users.get(username) if not user: return False delete_user = users.pop(username) self.__save(data=users, path=self.user_json) return delete_user # 读取奖品文件内容 def __red_gift(self): with open(self.gift_json, 'r') as f: data = json.loads(f.read()) return data # 奖品结构初始化 def __init_gift(self): data = { 'level1': { 'level1': {}, 'level2': {}, 'level3': {} }, 'level2': { 'level1': {}, 'level2': {}, 'level3': {} }, 'level3': { 'level1': {}, 'level2': {}, 'level3': {} }, 'level4': { 'level1': {}, 'level2': {}, 'level3': {} } } gifts = self.__red_gift() if len(gifts) != 0: return self.__save(data=data, path=self.gift_json) def __check_and_getgift(self, first_level, second_level, gift_name): if first_level not in FIRSTLEVELS: raise LevelError('first level not exists: %s' % first_level) if second_level not in SECONDLEVELS: raise LevelError('second level not exists: %s' % second_level) gifts = self.__red_gift() level_one = gifts[first_level] # 获取level的对象"level1": {"level1": {}, "level2": {}}, "level3": {}} level_two = level_one[second_level] # 获取level2的对象"level2": {} if gift_name not in level_two: return False return { 'level_one': level_one, 'level_two': level_two, 'gifts': gifts } # 定义一个写入的函数 def __save(self, data, path): json_data = json.dumps(data) with open(path, 'w') as f: f.write(json_data) # 添加奖品到gift_json文件 def __write_gift(self, first_level, second_level, gift_name, gift_count): if first_level not in FIRSTLEVELS: raise LevelError('first level not exists: %s' % first_level) if second_level not in SECONDLEVELS: raise LevelError('second level not exists: %s' % second_level) gifts = self.__red_gift() current_gift_pool = gifts[first_level] # 获取level的对象"level1": {"level1": {}, "level2": {}}, "level3": {}} current_second_gift_pool = current_gift_pool[second_level] # 获取level2的对象"level2": {} # 如果传入的count小于等于0,那就默认count为1 if gift_count <= 0: gift_count = 1 # 如果添加的奖品已经存在奖品库,那么就把添加的商品库存+1 if gift_name in current_second_gift_pool: current_second_gift_pool[gift_name]['count'] = current_second_gift_pool[gift_name]['count'] + gift_count else: # 如果添加的商品不在奖品库,那就把奖品写入文件 current_second_gift_pool[gift_name] = { 'name': gift_name, 'count': gift_count } # 还原level2的文件内容 current_gift_pool[second_level] = current_second_gift_pool # 还原level1的文件内容 gifts[first_level] = current_gift_pool # 编码为json以及写入json文件 self.__save(data=gifts, path=self.gift_json) # 修改奖品count数量 def __update_gift(self, first_level, second_level, gift_name, gift_count): data = self.__check_and_getgift( first_level=first_level, second_level=second_level, gift_name=gift_name ) if not data: return data current_gift_pool = data.get('level_one') current_second_gift_pool = data.get('level_two') gifts = data.get('gifts') current_gift = current_second_gift_pool[gift_name] if current_gift['count'] - gift_count < 0: raise NegativeNumberError('gift count can not nagative') current_gift['count'] -= gift_count current_second_gift_pool[gift_name] = current_gift current_gift_pool[second_level] = current_second_gift_pool gifts[first_level] = current_gift_pool self.__save(gifts, self.gift_json) def __delete_gift(self, first_level, second_level, gift_name): data = self.__check_and_getgift( first_level=first_level, second_level=second_level, gift_name=gift_name ) if not data: return data current_gift_pool = data.get('level_one') current_second_gift_pool = data.get('level_two') gifts = data.get('gifts') delete_gifts = current_second_gift_pool.pop(gift_name) current_gift_pool[second_level] = current_second_gift_pool gifts[first_level] = current_gift_pool self.__save(gifts, self.gift_json) return delete_gifts if __name__ == "__main__": gift_path = os.path.join(os.getcwd(), 'storage', 'gift.json') user_path = os.path.join(os.getcwd(), 'storage', 'user.json') a = Base(user_json=user_path, gift_json=gift_path) a.write_gift(first_level='level1', second_level='level1', gift_name='老闫的臭脚', gift_count=1000)
下面的是我自定义的异常类型,上面代码有用的,一块贴出来吧:
# coding:utf-8 """ 自定义异常方法 """ # 自定义路径不存在异常 class NotPathError(Exception): def __init__(self, message): self.message = message # 自定义文件格式不正确异常 class FormatError(Exception): def __init__(self, message): self.message = message # 自定义是否是文件类型异常 class NotFileError(Exception): def __init__(self, message): self.message = message class UserExistsError(Exception): def __init__(self, message): self.message = message class RoleError(Exception): def __init__(self, message): self.message = message class LevelError(Exception): def __init__(self, message): self.message = message class NegativeNumberError(Exception): def __init__(self, message): self.message = message class NotUserError(Exception): def __init__(self, message): self.message = message class UserActiveError(Exception): def __init__(self, message): self.message = message class CountError(Exception): def __init__(self, message): self.message = message
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?