使用 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 获取 Linux 系统信息的代码
Jul 13 Python
python通过colorama模块在控制台输出彩色文字的方法
Mar 19 Python
Python cookbook(数据结构与算法)将序列分解为单独变量的方法
Feb 13 Python
python实现对指定输入的字符串逆序输出的6种方法
Apr 26 Python
Python迭代器定义与简单用法分析
Apr 30 Python
python中使用iterrows()对dataframe进行遍历的实例
Jun 09 Python
python实现顺时针打印矩阵
Mar 02 Python
python多线程使用方法实例详解
Dec 30 Python
python正则过滤字母、中文、数字及特殊字符方法详解
Feb 11 Python
pytorch之Resize()函数具体使用详解
Feb 27 Python
Python网页解析器使用实例详解
May 30 Python
python Pexpect模块的使用
Dec 25 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
php异常处理技术,顶级异常处理器
2012/06/13 PHP
php使用curl出现Expect:100-continue解决方法
2015/03/03 PHP
thinkphp5.1 文件引入路径问题及注意事项
2018/06/13 PHP
PHP中Session ID的实现原理实例分析
2019/08/17 PHP
如何简单地用YUI做JavaScript动画
2007/03/10 Javascript
用JTrackBar实现的模拟苹果风格的滚动条
2007/08/06 Javascript
javascript 写类方式之一
2009/07/05 Javascript
由JavaScript技术实现的web小游戏(不含网游)
2010/06/12 Javascript
Table冻结表头示例代码
2013/08/20 Javascript
cookie的复制与使用记住用户名实现代码
2013/11/04 Javascript
JS+CSS实现带关闭按钮DIV弹出窗口的方法
2015/02/27 Javascript
javascript制作sql转换为stringBuffer的小工具
2015/04/03 Javascript
javascript实现画不相交的圆
2015/04/07 Javascript
javascript控制图片播放的实现代码
2020/07/29 Javascript
JS+CSS实现简单的二级下拉导航菜单效果
2015/09/21 Javascript
下一代Bootstrap的5个特点 超酷炫!
2016/06/17 Javascript
JavaScript函数表达式详解及实例
2017/05/05 Javascript
webpack中CommonsChunkPlugin详细教程(小结)
2017/11/09 Javascript
JavaScript获取移动设备型号的实现代码(JS获取手机型号和系统)
2018/03/10 Javascript
jQuery实现的上传图片本地预览效果简单示例
2018/03/29 jQuery
vue-cli3.0使用及部分配置详解
2018/08/29 Javascript
vue项目动态设置页面title及是否缓存页面的问题
2018/11/08 Javascript
[01:04:14]OG vs Winstrike 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
[04:59]DOTA2-DPC中国联赛 正赛 Ehome vs iG 选手采访
2021/03/11 DOTA
python实时监控cpu小工具
2018/06/21 Python
详解Django-restframework 之频率源码分析
2019/02/27 Python
Django Sitemap 站点地图的实现方法
2019/04/29 Python
详解Python下载图片并保存本地的两种方式
2019/05/15 Python
Python GUI库PyQt5图形和特效样式QSS介绍
2020/02/25 Python
windows下的pycharm安装及其设置中文菜单
2020/04/23 Python
CSS3实现的闪烁跳跃进度条示例(附源码)
2013/08/19 HTML / CSS
Python如何定义一个函数
2015/09/01 面试题
学前教育学生自荐信范文
2013/12/31 职场文书
校园新闻广播稿
2014/01/10 职场文书
如何使用vue3打造一个物料库
2021/05/08 Vue.js
Vue2项目中对百度地图的封装使用详解
2022/06/16 Vue.js