场景编程集锦 - 大奖在招手,你要HOLD住

时间:2023-01-13 18:59:54

场景描述

  2022年12月7日注定会是一个里程碑的日子。因为从这一天开始,我们真正走出了新冠疫情的阴霾。经济开始逐渐复苏,民生有了烟火气,城市商业中心和购物广场开始回归和再现疫情之前的繁华热闹景象。瞧,寰银购物广场正在开展2023年新春促销活动。在青春美少女组合表演了精彩劲爆的暖场舞蹈之后,帅气的活动主持人开始粉墨登场:“大奖在招手,你要HOLD住”。当主持人宣布本次活动的特等奖品是价值20万的新能源轿车时,瞬间引爆了现场一片片的尖叫声。主持人卖力而讨好地调动现场的气氛,抽奖现场聚集了无数的消费者和围观的市民,人气越来越旺。根据“大奖在招手”活动规定:凡是在寰银购物广场购物消费合计金额满1000元者,均可以参与现场抽奖,保证抽奖必中奖。这样久违的现场促销活动还是吸引了众多市民的眼球,激发了消费热情,拉动了消费的增长。   下面就我们使用Python开发一个商场购物现场抽奖程序,来模拟和再现购物抽奖的火爆场景。


编程思路

抽奖程序需要明确和解决以下问题:

2.1 抽奖资格认定

根据购物小票金额加总合计数,由现场人工进行抽奖资格的认定,不用程序实现。

2.2 奖品池表示

我们可以使用Python的数据结构列表来存放奖品。列表的每一个元素,就代表一项奖品。

2.3 抽奖

可以使用random随机处理模块,实现从奖品池随机选取奖品。也就是从奖品池列表中随机选择一个元素。

2.4 补充奖品

根据实际需要,及时向奖品池中添加奖品,实际上就是实现对奖品池列表添加元素。

2.5 查询奖品

列出奖品池中前10个奖品,显示奖品池列表中的前10个元素。


代码实现

  整个抽奖程序由两个模块组成:一个是prizes.py,主要是实现抽奖的一些基础性的公共函数;另一个模块big_prize.py则是抽奖程序的主程序。   模块prizes.py源代码程序如下所示:

"""
  prizes.py : 大奖在招手公共模块
"""
import random

def make_pool(prz_list):
    """创建奖品池"""
    prz_pool = []
    for prize, amount in prz_list:   # ①
        for i in range(amount):
            prz_pool.append(prize)

    random.shuffle(prz_pool)  # ②
    return prz_pool

def lottery(prizes):
    """ 开始抽奖 """
    if prizes:
        prize = random.choice(prizes)   # ③
        print('恭喜中奖:'+prize)
        prizes.remove(prize)    # ④
    else:
        print('没有奖品啦!')
    return prizes

def append_prize(prizes):
    """ 追加奖品 """
    while True:
        try:
            prize_name = input('名称:')
            amount = int(input('数量:'))
            break
        except ValueError:
            print('数量:数据类型错!')

    prizes += [prize_name] * amount  # ⑤ 
    random.shuffle(prizes)
    return prizes

def print_prize(prizes):
    """打印前10奖品"""
    if prizes:
        for num, prize in enumerate(prizes[:10]):
            print(str(num + 1) + "\t" + prize)
    else:
        print('没有奖品啦!')

主要函数功能介绍如下: 函数make_pool(prz_list):根据奖品清单prz_list,创建一个奖品池,并作为函数的返回值。 函数lottery(prizes):实现随机抽奖,并且删除已抽取的奖品,更新奖品池。 函数append_prize(prizes):向奖品池添加奖品,并对奖品池进行随机排列。 函数print_prize(prizes):实现奖品池中前10项奖品的打印输出。 重要语句如下: 语句①通过双重循环实现奖品池的创建。 语句②随机排列奖品。 语句③实现随机抽取奖品。 语句④把已抽奖的奖品移除奖品池,实现奖品池的更新。 语句⑤添加到奖品池中。

  模块big_prize.py程序源代码如下:

"""
  big_prize.py : 大奖在招手
"""
from common.prizes import *   # ①
prize_list = [('3D 眼镜', 20), ('AI 音箱', 30), ('数字录音笔', 20), ('迷你投影仪', 20), ('手机自拍杆', 10)]  # ②

def main():
    prizes = make_pool(prize_list)  # ③ 
    while True:
        cmd = input("L - 开始抽奖,  A - 补充奖品,  P - 查询奖品,  Q - 退出程序: ")
        if cmd.lower() == 'q':
            break
        elif cmd.lower() == 'l':
            prizes = lottery(prizes)   # ④
        elif cmd.lower() == 'a':  
            prizes = append_prize(prizes)   # ⑤
        elif cmd.lower() == 'p': 
            print_prize(prizes)   # ⑥

if __name__ == '__main__':
    main()

重要语句说明如下: 语句①导入抽奖程序的基础模块prizes.py的所有函数,主要这个模块是存放common包中的。 语句②定义一个奖品清单的列表,包括每种奖品名称和数量。我们后续将使用它创建初始的奖品池。 语句③根据奖品清单,创建奖品池。 语句④开始抽奖。 语句⑤追加奖品。 语句⑥打印前个10奖品


执行效果

4.1 程序目录结构

D:\cases\大奖在招手>dir
2022/12/09  13:11               784 big_prize.py
2022/12/09  13:12    <DIR>          common
D:\cases\大奖在招手>
D:\cases\大奖在招手\common> cd common
D:\cases\大奖在招手\common>
D:\cases\大奖在招手\common>dir
2022/12/09  13:12             1,196 prizes.py
2022/04/01  07:34               106 __init__.py
D:\cases\大奖在招手\common>

因为在子目录common中定义了一个__init__.py文件,所以common是Python的一个包。

4.2 程序执行效果

D:\cases\大奖在招手>python big_prize.py
L - 开始抽奖,  A - 补充奖品,  P - 查询奖品,  Q - 退出程序: l
恭喜中奖:数字录音笔
L - 开始抽奖,  A - 补充奖品,  P - 查询奖品,  Q - 退出程序: l
恭喜中奖:3D 眼镜
L - 开始抽奖,  A - 补充奖品,  P - 查询奖品,  Q - 退出程序: p
1       AI 音箱
2       迷你投影仪
3       迷你投影仪
4       3D 眼镜
5       手机自拍杆
6       AI 音箱
7       3D 眼镜
8       3D 眼镜
9       AI 音箱
10      迷你投影仪
L - 开始抽奖,  A - 补充奖品,  P - 查询奖品,  Q - 退出程序: q

D:\cases\大奖在招手>

程序优化

  截至目前,商场抽奖程序实现了设计目标,但程序执行不太方便,程序处理逻辑有待优化:   首先,程序每次启动,均要重新创建奖品池,与实际场景不符。   其次,程序正常结束或退出时,奖品池的内容丢失;   再其次,将初始的奖品清单以文本文件形式存放,相对于现在的列表常量prize_list存放来说,实现了程序和数据的分离,增强了程序的灵活性。我们可以使用诸如Windows记事本这样的编辑程序,就可以修改奖品及数量,而不用修改程序big_prize.py,就能够实现初始化奖品池的内容。   最后,目前这一版程序是基于字符界面,程序界面不够美观。   第一个问题解决办法很简单,就是把big_prize.py中的语句③移入到while循环中,作为一个单独的功能选项,这样就可以根据需要,选择性地创建奖品池。   第二个问题的解决方法是在退出程序之前,把奖品池列表的内容保存到文件中,而在程序启动时读入文件保存的内容,将数据恢复到奖品池列表中。这里可以有多种方案可供选择,除了你可以使用文本文件保存奖品信息外,还有以下三个方案:   方案一是使用Python 的shelve模块。   使用Python的shelve模块,它可以将Python支持的变量,特别是各种对象变量例如列表、字典等写入到磁盘上的一个二进制文件中,以及提供逆向过程的功能,你的程序也可以从磁盘文件中快速恢复变量的数据。   方案二是使用Python 的json模块。   通过使用Python的json模块,可以非常简单地对程序中的变量进行读和写操作;它是使用JSON格式的文件存放奖品池的数据,JSON格式的文件特别适合于在不同的编程语言之间进行数据交换处理,例如前端程序和后台程序之间交换数据。   方案三是使用sqlite3数据库。   你完全可以选择使用数据库的存储方。Python自带一个轻量级的数据库sqlite3,使用方便快捷,应用范围广泛。我们常常能在嵌入式编程和浏览器中看到sqlite3的应用场景,我个人认为在本案例中使用数据库管理系统,有点大材小用,“杀鸡焉用牛刀”。   综上所述,我们建议使用Python的标准模块shelve,它可以简单优雅地将Python的数据结构存入文件,并且在你需要时候快捷地从文件中加载这些数据。   第三个问题的解决方案已经很明确了,我们需要新增一个函数,实现从文本文件或者shelve文件中读入奖品及数量,以此动态地创建奖品列表prize_list。需要注意的是每一个列表元素就是一个元组,包含奖品名称和奖品数量。   至于最后一个问题,Python提供了多种图形界面程序开发的解决方案。这些方案包括: Tkinter,wxPython和PyQt。其中Tkinter 是Python官方提供,轻量级的GUI开发工具。PyQt,wxPython 功能很强大。它们为快速开发桌面图形界面应用程序提供了强大的工具支持。结合本案例的具体情况,我们建议是使用Python原生图形开发库tkinter,对模块big_prize.py进行修改,实现图形应用程序界面的开发,有兴趣的读者不妨一试,你一定会有全新的收获。


场景扩展

  在案例中实现的商场抽奖程序还适用于:企业/公司春晚演唱现场抽奖、各种团建活动的抽奖应用场景。