使用 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实现的下载8000首儿歌的代码分享
Nov 21 Python
在Python编程过程中用单元测试法调试代码的介绍
Apr 02 Python
探究Python中isalnum()方法的使用
May 18 Python
Python多维/嵌套字典数据无限遍历的实现
Nov 04 Python
Python随机生成均匀分布在单位圆内的点代码示例
Nov 13 Python
解决Pandas to_json()中文乱码,转化为json数组的问题
May 10 Python
python读取目录下所有的jpg文件,并显示第一张图片的示例
Jun 13 Python
在Pandas中处理NaN值的方法
Jun 25 Python
python关于调用函数外的变量实例
Dec 26 Python
在TensorFlow中屏蔽warning的方式
Feb 04 Python
python编写实现抽奖器
Sep 10 Python
浅析Python OpenCV三种滤镜效果
Apr 11 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/04/24 PHP
PHP开源开发框架ZendFramework使用中常见问题说明及解决方案
2014/06/12 PHP
WordPress开发中的get_post_custom()函数使用解析
2016/01/04 PHP
PHP文件缓存smarty模板应用实例分析
2016/02/26 PHP
thinkPHP内置字符串截取函数用法详解
2016/11/15 PHP
Javascript valueOf 使用方法
2008/12/28 Javascript
MC Dialog js弹出层 完美兼容多浏览器(5.6更新)
2010/05/06 Javascript
JavaScript使用IEEE 标准进行二进制浮点运算产生莫名错误的解决方法
2011/05/28 Javascript
Firefox/Chrome/Safari的中可直接使用$/$$函数进行调试
2012/02/13 Javascript
JQuery分别取得每行最后一列和最后一行的示例代码
2013/08/18 Javascript
JQuery中serialize()、serializeArray()和param()方法示例介绍
2014/07/31 Javascript
js匿名函数的调用示例(形式多种多样)
2014/08/20 Javascript
Javascript中拼接大量字符串的方法
2015/02/05 Javascript
jQuery实现个性翻牌效果导航菜单的方法
2015/03/09 Javascript
SWFUpload多文件上传及文件个数限制的方法
2016/05/31 Javascript
js监听input输入框值的实时变化实例
2017/01/26 Javascript
一文让你彻底搞清楚javascript中的require、import与export
2017/09/24 Javascript
nodejs acl的用户权限管理详解
2018/03/14 NodeJs
ES6使用export和import实现模块化的方法
2018/09/10 Javascript
ECharts地图绘制和钻取简易接口详解
2019/07/12 Javascript
解决Vue 刷新页面导航显示高亮位置不对问题
2019/12/25 Javascript
JS三级联动代码格式实例详解
2019/12/30 Javascript
vue商城中商品“筛选器”功能的实现代码
2020/07/01 Javascript
[01:10:48]完美世界DOTA2联赛PWL S2 GXR vs PXG 第一场 11.18
2020/11/18 DOTA
用Python实现通过哈希算法检测图片重复的教程
2015/04/02 Python
用Pygal绘制直方图代码示例
2017/12/07 Python
Django 实现前端图片压缩功能的方法
2019/08/07 Python
Python使用py2neo操作图数据库neo4j的方法详解
2020/01/13 Python
Python2及Python3如何实现兼容切换
2020/09/01 Python
面试后的感谢信范文
2014/02/01 职场文书
党支部创先争优活动总结
2014/08/28 职场文书
2014年幼儿园园长工作总结
2014/12/17 职场文书
公司管理建议书
2015/09/14 职场文书
2016国培学习心得体会
2016/01/08 职场文书
导游词之日月潭
2019/11/05 职场文书
Linux中文件的基本属性介绍
2022/06/01 Servers