使用 Python 写一个简易的抽奖程序


Posted in Python onDecember 08, 2019

使用 Python 写一个简易的抽奖程序

不知道有多少人是被这个头图骗进来的:)

事情的起因是这样的,上周有同学问小编,看着小编的示例代码敲代码,感觉自己也会写了,如果不看的话,七七八八可能也写的出来,但是一旦自己独立写一段程序,感觉到无从下手。

其实这个很正常,刚开始学习写代码,都是跟着别人的套路往下写,看的套路少,很难形成自己的套路,这就和做数学题是一样的,做一道题就想会所有的题目,这个可能性微乎其微,都是通过大量的练习来摸索到自己的套路。

正好快过年了,各个公司都会搞一些抽奖活动,小编今天就来聊一下,如果要写一个简单的抽奖程序,小编是怎么写的。

分析需求

我们先整理下思路,目标是什么?

目标是要写一个抽奖程序,那么抽奖程序的核心是什么?

当然是如何判断一个人中奖了。那么如何判断一个人中奖呢?

是不是可以通过随机函数来操作呢?

中奖方法

一步一步来,我们先通过随机函数来判断是否中奖。代码是不是可以先写成下面这样:

import random

# 判断中奖函数
def lottery():
 flag = random.randint(0, 9)
 if flag < 2:
 return True
 else:
 return False

首先,我们获取 0 ~ 9 之间的随机正整数(这里不讨论 random 是不是真随机,从狭义上来讲我们可以认为它是随机的),如果中奖率为 20% 的话,我们可以认为小于 2 的数字为中奖,其余的为没有中奖。然后中奖后返回 True ,没有中奖返回 False 。

我们加一个入口测试函数,测试一下上面的代码是否能正常运行,并且中奖率是否能维持在大约 20 % 左右。

if __name__ == '__main__':
 # 中奖次数
 a = 0
 # 没有中奖次数
 b = 0
 for i in range(1000000) :
 if (lottery()):
  a += 1
 else:
  b += 1

 print('共计中奖:', a, ',未中奖:', b)

执行结果:

共计中奖: 200145 ,未中奖: 799855

上面的测试总共循环了 1 百万次,大约执行需要 2 ~ 3 秒左右,速度还是蛮快的。可以看到,中奖结果确实接近 20% 左右。

动态中奖率

难道到这里就结束了么?当然不可能,这里只是刚刚开了个头。

如果这时老板说,你这个概率不能调整啊,需要让中奖率可以动态调整的,活动刚开始的时候中奖率要高,随着时间的推移,中奖率要降下来。

这时候咋整,傻眼了吧。

既然中奖率要可调整,那么我们中奖率就不能定死在程序中了,这个中奖率需要有一个地方去做存储,在每次做随机的时候将这个中奖率取出来。

简单易行的方法就是将这个中奖率放在数据库中或者缓存服务中,这个根据实际业务场景来定。一般是根据预估访问压力的大小来进行技术选型,如果压力不是特别大,那么放在数据库中也是可以的,如果并发会比较高的话,建议还是放在缓存中。

我们来写一个从数据库获取中奖概率的方法(为了展示直观,小编这里直接使用 Mysql 数据库用作数据存储),先看下数据库的数据:

使用 Python 写一个简易的抽奖程序

很简单的设计了一张表,里面有意义的字段有两个,一个用作中奖率的分子部分,一个用作中奖率的分母部分。分母部分最好要设置成 100 、 1000 、 10000 这种,这样计算中奖率会比较好计算。

def get_lottery_rate():
 conn = pymysql.connect(host='localhost', user='root', password='password', database='test', charset='utf8mb4')
 try:
 sql = 'SELECT fenzi, fenmu FROM rate'
 cursor = conn.cursor()
 cursor.execute(sql)
 result = cursor.fetchone()
 return result
 except Exception as ex:
 print(ex)
 finally:
 conn.close()

运行这个方法测试结果如下:

(10, 100)

可以看到,我们获得了一个元组,里面的内容就是我们从数据库取出来的分子和分母。

我们将前面的抽奖的那个方法改一下,改成从数据库获取中奖比例。修改后的代码如下:

def lottery():
 rate = get_lottery_rate()
 flag = random.randint(1, rate[1])
 if flag < rate[0]:
 return True
 else:
 return False

还是运行上面的测试方法,这里要注意下,因为我们现在是从数据库获取数据,每次方法执行都要加上数据库链接的建立与销毁,建议将循环次数修改为 1000 以内,不然执行的时间就有点太长了。

小编这里将循环次数修改为 1000 次后,执行结果如下:

共计中奖: 92 ,未中奖: 908

那么到这里,我们就可以通过修改数据库中数据实时的操作中奖率了。当然上面的慢的问题我们可以使用数据库连接池等技术进行优化。

增加奖项

那么是否就结束了呢?no no no,我们接着加需求。

现在,我们只能知道每次到底中不中奖,只有一个奖项,但是现在想变成 3 个奖项,如:一等奖、二等奖、三等奖那该怎么办?

这个对之前的抽奖方法改动就有点大了,首先我们先在数据库增加出来另外两个奖项的配置:

使用 Python 写一个简易的抽奖程序

配置这里三个奖项的分母最好保持一致,否则后续计算会徒增复杂度。

修改我们获取配置的那个方法:

def get_lottery_rate():
 conn = pymysql.connect(host='localhost', port = 3306, user='root', password='password', database='test', charset='utf8mb4')
 try:
 sql = 'SELECT * FROM rate order by id asc '
 cursor = conn.cursor()
 cursor.execute(sql)
 result = cursor.fetchall()
 return result
 except Exception as ex:
 print(ex)
 finally:
 conn.close()

测试调用后结果如下:

((1, 10, 100), (2, 5, 100), (3, 1, 100))

先在我们要做的是要将这个配置融入进我们之前的中奖的那个方法中,不多说,直接上代码:

# 判断中奖函数
def lottery():
 config = get_lottery_rate()
 flag = random.randint(1, config[0][2])
 if flag <= config[0][1]:
 return 1
 elif flag > config[0][1] and flag <= (config[1][1] + config[0][1]):
 return 2
 elif flag > (config[1][1] + config[0][1]) and flag <= (config[2][1] + config[1][1]):
 return 3
 else:
 return 0

接着修改我们的做测试的代码:

def main():
 # 一等奖中奖次数
 a = 0
 # 二等奖中奖次数
 b = 0
 # 三等奖中奖次数
 c = 0
 # 未中奖次数
 d = 0
 # 循环次数
 e = 0
 for i in range(1000):
 e += 1
 print('当前循环次数:', e)
 result = lottery()
 print('当前中奖结果:', result)
 if (result == 1):
  a += 1
 elif (result == 2):
  b += 1
 elif (result == 3):
  c += 1
 else:
  d += 1

 print('一等奖中奖:', a, ',二等奖中奖次数:', b, ',三等奖中奖次数:', c, ',未中奖次数:', d)

调用我们的测试方法:

if __name__ == '__main__':
 main()

小编这里的运行结果如下:

使用 Python 写一个简易的抽奖程序

增加会员判断

到这里我们还没完,还能加需求,现在网站大多数都是会员制的,比如白银会员,黄金会员,钻石会员,如果不同的会员等级需要有不同的中奖率,这个是很正常的一件事儿,小编现在还清晰的记得当年某家大型互联网公司代码中的注释 “穷逼 VIP(活动送的那种)” 。

我们假设钻石会员的中奖率为整体中奖率的 100% ,黄金会员的中奖率为整体中奖率的 50% ,白银会员的中奖率为整体中奖率的 20% 。

最简单的实现方式是直接在最外层套一层会员中奖率的判断,不知道各位同学怎么想。

小编这里给出自己的解决方案:

# 判断会员等级中奖率过滤
# 会员等级 1.白银会员 2.黄金会员 3. 钻石会员
def vip_lottery(level):
 rate = random.randint(1, 10)
 # 如果是钻石会员,直接进入抽奖函数
 if level == 3:
 return lottery()
 # 如果是黄金会员, 50% 概率进入抽奖函数
 elif level == 2:
 if rate <= 5:
  return lottery()
 else:
  return 0
 # 如果是白银会员, 20% 概率进入抽奖函数
 elif level == 1:
 if rate <= 2:
  return lottery()
 else:
  return 0
 # 如果是其他,直接返回未中奖
 else:
 return 0

我们新增一个测试增加会员过滤的测试方法:

# 会员制中奖测试方法
def test_vip():
 print('请输入您当前的会员等级:1.白银会员 2.黄金会员 3. 钻石会员')
 level = input()
 result = vip_lottery(int(level))
 if (result == 1):
 print('恭喜您中了一等奖')
 elif (result == 2):
 print('恭喜您中了二等奖')
 elif (result == 3):
 print('恭喜您中了三等奖')
 else:
 print('未中奖,谢谢惠顾')

在我们的入口函数中调用这个方法:

if __name__ == '__main__':
 test_vip()

最终测试结果如下:

使用 Python 写一个简易的抽奖程序

小编的人品还可以嘛,直接就能中三等奖。

那么,到这里,是不是一个简易的抽奖程序就算完成了呢?其实还能接着加,如果每个奖项都有数量限制,并且限制的数量是可以随时调整的等等等等,小编这里就不一一列举了。

整体代码写的稍微有些长了,小编就不贴出来了,上传到代码仓库各位感兴趣的同学自己访问吧。

注意: 本篇文章所使用代码,仅供演示讲解使用,不可用于生产环境,在访问量过大的情况下会产生严重的性能问题。

示例代码

示例代码-Github

示例代码-Gitee

总结

以上所述是小编给大家介绍的使用 Python 写一个简易的抽奖程序,希望对大家有所帮助!

Python 相关文章推荐
python中文编码问题小结
Sep 28 Python
Python中模拟enum枚举类型的5种方法分享
Nov 22 Python
python实现分析apache和nginx日志文件并输出访客ip列表的方法
Apr 04 Python
Python实现简单拆分PDF文件的方法
Jul 30 Python
Python实现备份MySQL数据库的方法示例
Jan 11 Python
python处理csv数据动态显示曲线实例代码
Jan 23 Python
PyQt5打开文件对话框QFileDialog实例代码
Feb 07 Python
python实现beta分布概率密度函数的方法
Jul 08 Python
pycharm修改file type方式
Nov 19 Python
python列表推导式入门学习解析
Dec 02 Python
PyCharm2020.1.1与Python3.7.7的安装教程图文详解
Aug 07 Python
pandas将list数据拆分成行或列的实现
Dec 13 Python
布隆过滤器的概述及Python实现方法
Dec 08 #Python
Python+Redis实现布隆过滤器
Dec 08 #Python
PyCharm 2019.3发布增加了新功能一览
Dec 08 #Python
使用tqdm显示Python代码执行进度功能
Dec 08 #Python
Python tkinter实现图片标注功能(完整代码)
Dec 08 #Python
Python中six模块基础用法
Dec 08 #Python
python实现布隆过滤器及原理解析
Dec 08 #Python
You might like
如何让CI框架支持service层
2014/10/29 PHP
详解YII关联查询
2016/01/10 PHP
Laravel中服务提供者和门面模式的入门介绍
2017/11/06 PHP
php实现根据身份证获取精准年龄
2020/02/26 PHP
基于jquery的lazy loader插件实现图片的延迟加载[简单使用]
2011/05/07 Javascript
深入理解JavaScript系列(6) 强大的原型和原型链
2012/01/15 Javascript
将nodejs打包工具整合到鼠标右键的方法
2013/05/11 NodeJs
JS window对象的top、parent、opener含义介绍
2013/12/03 Javascript
教你如何使用firebug调试功能了解javascript闭包和this
2015/03/04 Javascript
javascript特效实现——当前时间和倒计时效果的简单实例
2016/07/20 Javascript
js表单元素checked、radio被选中的几种方法(详解)
2016/08/22 Javascript
canvas实现手机端用来上传用户头像的代码
2016/10/20 Javascript
VUE2.0中Jsonp的使用方法
2018/05/22 Javascript
javascript验证form表单数据的案例详解
2019/03/25 Javascript
Vuex的热更替如何实现
2020/06/05 Javascript
ElementUI 修改默认样式的几种办法(小结)
2020/07/29 Javascript
详解Python3.6的py文件打包生成exe
2018/07/13 Python
selenium+python实现自动化登录的方法
2018/09/04 Python
对Python 内建函数和保留字详解
2018/10/15 Python
python 实现在一张图中绘制一个小的子图方法
2019/07/07 Python
HTML5通用接口详解
2016/06/12 HTML / CSS
AC Lens:购买隐形眼镜
2017/02/26 全球购物
生产班组长岗位职责
2014/01/05 职场文书
xxx同志考察材料
2014/02/07 职场文书
消防战士优秀事迹材料
2014/02/13 职场文书
活动总结怎么写
2014/04/28 职场文书
关爱留守儿童标语
2014/06/18 职场文书
本科毕业生应聘求职信
2014/07/06 职场文书
向国旗敬礼活动总结
2014/09/27 职场文书
教师党的群众路线教育实践活动剖析材料
2014/10/09 职场文书
基层党员学习党的群众路线教育实践活动心得体会
2014/11/04 职场文书
2014年学生会个人工作总结
2014/11/07 职场文书
优秀教师推荐材料
2014/12/16 职场文书
经验交流材料格式
2014/12/30 职场文书
遗愿清单观后感
2015/06/09 职场文书
Windows Server 2012 R2 磁盘分区教程
2022/04/29 Servers