使用 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实现批量压缩图片
Jan 25 Python
使用Python爬取最好大学网大学排名
Feb 24 Python
Python3爬虫学习之将爬取的信息保存到本地的方法详解
Dec 12 Python
对Python中创建进程的两种方式以及进程池详解
Jan 14 Python
使用python爬取微博数据打造一颗“心”
Jun 28 Python
Python符号计算之实现函数极限的方法
Jul 15 Python
详解Python可视化神器Yellowbrick使用
Nov 11 Python
Python过滤序列元素的方法
Jul 31 Python
基于logstash实现日志文件同步elasticsearch
Aug 06 Python
python爬虫中采集中遇到的问题整理
Nov 27 Python
pytorch中index_select()的用法详解
Jan 06 Python
Python 数据可视化之Seaborn详解
Nov 02 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 服务器配置(使用Apache及IIS两种方法)
2009/06/01 PHP
php preg_filter执行一个正则表达式搜索和替换
2012/02/27 PHP
PHP imagecreatefrombmp 从BMP文件或URL新建一图像
2012/07/16 PHP
PHP使用SWOOLE扩展实现定时同步 MySQL 数据
2017/04/09 PHP
php 数组元素快速去重
2017/05/05 PHP
Prototype Object对象 学习
2009/07/12 Javascript
Javascript实现CheckBox的全选与取消全选的代码
2010/07/20 Javascript
javaScript 删除字符串空格多种方法小结
2012/10/24 Javascript
JavaScript1.6数组新特性介绍以及JQuery的几个工具方法
2013/12/06 Javascript
js获得参数的getParameter使用示例
2014/02/26 Javascript
JS制作简单的三级联动
2015/03/18 Javascript
jquery实现仿新浪微博带动画效果弹出层代码(可关闭、可拖动)
2015/10/12 Javascript
详解JavaScript的另类写法
2016/04/11 Javascript
JavaScript中setter和getter方法介绍
2016/07/11 Javascript
简单的js计算器实现
2016/10/26 Javascript
详解jQuery lazyload 懒加载
2016/12/19 Javascript
基于Bootstrap的网页设计实例
2017/03/01 Javascript
php输出全部gb2312编码内的汉字方法
2017/03/04 Javascript
vue注册组件的几种方式总结
2018/03/08 Javascript
VUE 实现动态给对象增加属性,并触发视图更新操作示例
2019/11/29 Javascript
[52:57]2014 DOTA2国际邀请赛中国区预选赛 LGD-CDEC VS HGT
2014/05/21 DOTA
python发送伪造的arp请求
2014/01/09 Python
Pandas探索之高性能函数eval和query解析
2017/10/28 Python
Python unittest单元测试框架总结
2018/09/08 Python
Python中使用遍历在列表中添加字典遇到的坑
2019/02/27 Python
PyQt QListWidget修改列表项item的行高方法
2019/06/20 Python
在linux下实现 python 监控usb设备信号
2019/07/03 Python
Python 从subprocess运行的子进程中实时获取输出的例子
2019/08/14 Python
python3.6.8 + pycharm + PyQt5 环境搭建的图文教程
2020/06/11 Python
Staples加拿大官方网站:办公用品一站式采购
2016/09/25 全球购物
德国购买踏板车网站:Microscooter
2019/10/14 全球购物
老师对学生的评语
2014/04/18 职场文书
生产操作工岗位职责
2014/09/16 职场文书
老员工辞职信范文
2015/05/12 职场文书
检察院起诉意见书
2015/05/20 职场文书
债务纠纷代理词
2015/05/25 职场文书