自学计划 - python 小白基础教程 - 第十二课:学生管理系统

目录

简介
第一课:python 的介绍
第二课:变量与操作符
第三课:字符串和数字
第四课:条件执行语句
第五课:列表与元组
第六课:循环语句
第七课:集合
第八课:字典
第九课:函数
第十课:面向对象
第十一课:文件的操作
第十二课:学生管理系统

需求概述

新的一个学期开始了,开学的第一天辅导员找到你,说班里学生太多,想让你帮着做一个学生管理系统。

你一想这不是很简单,
啪啪啪敲下了几行代码便交了上去。

# 用数据与字典结合的形式保存数据
data = []
while True:
    inp = input('请输入新增、查看或退出:\n')
    if inp == '新增':
        # 接收用户数据,并去除前后空格
        inp = input('输入姓名、性别、年龄,用空格作区分:\n').strip()
        name, gender, age = inp.split(' ')

        # 将数据拆分出来并以字典形式添加到数组中
        data.append(
            dict(
                name=name,
                gender=gender,
                age=age,
            )
        )
    elif inp == '查看':
        print('当前共有%s名学生' % len(data))
        # 循环打印数据
        for item in data:
            print(
                '姓名:{name},性别:{gender},年龄:{age}'.format(
                    name=item['name'], gender=item['gender'], age=item['age']
                )
            )
    elif inp == '退出':
        break
    else:
        print('输入错误请重新输入')

    print('\n')

你运用了之前所学到的知识,使用了列表与字典类型保存数据。
使用了 while 循环接收用户的操作, 用 input 接收输入并对其字符串拆分。

pickle 序列化

美美地等着辅导员夸奖的你,等来了辅导员的电话,他告诉你他花半小时录入的数据在重启程序后消失,
你一拍腿大呼忘记将其持久化到硬盘,于是便运用了上个章节学到的文件操作进行修改。

因为文件的操作写入时接收二进制或字符串类型,便需要将我们数组与字典组合的类型序列化成字符串加以保存。

什么是序列化?

序列化便是以一定规范将对象转成二进制或字符,等到需要时再将其解析回对象。
常在需要保存对象到文件或数据库,再或者网络传输时使用。

在这里我们使用内置的pickle模块来序列化和反序列化。

import os
import pickle

# 用大写变量名来表示一些常量
DATA_PATH = './data'

# 用数据与字典结合的形式保存数据
data = []

# 判断文件是否存在
if os.path.exists(DATA_PATH):
    with open(DATA_PATH, 'r') as f:
        data_str = f.read()
        data = pickle.loads(data_str)

while True:
    inp = input('请输入新增、查看或退出:\n')
    if inp == '新增':
        # 接收用户数据,并去除前后空格
        inp = input('输入姓名、性别、年龄,用空格作区分:\n').strip()
        name, gender, age = inp.split(' ')

        # 将数据拆分出来并以字典形式添加到数组中
        data.append(
            dict(
                name=name,
                gender=gender,
                age=age,
            )
        )
    elif inp == '查看':
        print('当前共有%s名学生' % len(data))
        # 循环打印数据
        for item in data:
            print(
                '姓名:{name},性别:{gender},年龄:{age}'.format(
                    name=item['name'], gender=item['gender'], age=item['age']
                )
            )
    elif inp == '退出':
        break
    else:
        print('输入错误请重新输入')

    print('\n')

with open(DATA_PATH, 'w') as f:
    f.write(pickle.dumps(data))

我们运用之前学到的知识,在一开始读取文件并用 loads 将二进制解析成数组。
并在之后退出程序时将 data 数组 dumps 成二进制。

在你刚写完的时候,辅导员来了电话,说他还需要更新数据功能。

你一寻思,辅导员是典型的甲方心态。一开始自己心里没个数,一会说加个功能,一会说修改个功能。

代码经常修改的话, 会影响到开发封闭原则,各模块相互引用如盘丝洞般错综复杂,不小心就变成了屎山。

所以你想到了可以面向对象的方式重构代码,面向对象的三大特征是抽象、继承、多态,可以让你很容易地应对之后的修改与功能的新增。

面向对象设计是对付不合理甲方的神器。

首先我们确定三个类。

class Student:
    # 学生对象
    def __init__(self, name, gender, age):
        pass

    def __str__(self):
        # 打印时的显示
        pass

class Op:
    # 所有操作类的父类

    @staticmethod
    def hander(data):
        raise NotImplementedError()

class Manager:
    # 负责程序的管理,数据的读取与保存

    def register(self, op):
        # 注册操作
        pass

    def unregister(self, op):
        # 取消注册
        pass

    def load(self):
        # 从文件读取数据
        pass


    def save(self):
        # 保存数据到文件
        pass

    def loop(self):
        # 执行循环
        pass

以上就是我们大致定义到的接口,针对其分别进行实现。

import os
import pickle

DATA_PATH = './data'


class Student:
    def __init__(self, name, gender, age):
        self.name = name
        self.gender = gender
        self.age = age

    def __str__(self):
        return '姓名:{name},性别:{gender},年龄:{age}'.format(
            name=self.name, gender=self.gender, age=self.age
        )

class Op:
    action = ''

    @staticmethod
    def handle(data):
        raise NotImplementedError()


class Manager:
    ops = {}
    data = []

    def __init__(self):
        self.load()

    def load(self):
        # 从文件读取数据
        # 判断文件是否存在
        if os.path.exists(DATA_PATH):
            with open(DATA_PATH, 'rb') as f:
                data_str = f.read()
            if data_str:
                self.data = pickle.loads(data_str)

    def save(self):
        # 保存数据到文件
        with open(DATA_PATH, 'wb') as f:
            f.write(pickle.dumps(self.data))

    def register(self, op):
        # 注册操作
        self.ops[op.action] = op

    def unregister(self, op):
        # 取消注册
        if op.action in self.ops:
            self.ops[op.action]

    def loop(self):
        # 执行循环
        while True:
            inp = input(
                '请输入%s或退出:\n' % ','.join([action for action in self.ops.keys()])
            )

            if inp == '退出':
                break
            if inp in self.ops:
                self.ops[inp].handle(self.data)
            else:
                print('输出错误')

        self.save()

我们完成了以上的东西, 这时我们定义一个 OpAdd 类 与 OpList 继承自 Op 类。
并将其注册到 manager 中,运行我们的程序。

class OpAdd(Op):
    action = '增加'

    @staticmethod
    def handle(data):
        inp = input('输入姓名、性别、年龄,用空格作区分:\n')
        name, gender, age = inp.split(' ')
        data.append(Student(name, gender, age))
        print('增加成功')
        return data


class OpList(Op):
    action = '查看'

    @staticmethod
    def handle(data):
        print('当前共有%s名学生' % len(data))
        # 循环打印数据
        for student in data:
            print(student)


manager = Manager()
manager.register(OpAdd)
manager.register(OpList)

# 执行
manager.loop()

到此完成了我们的程序,测试一下!

请输入增加,查看或退出:
增加
输入姓名、性别、年龄,用空格作区分:
小明 男 20
增加成功
请输入增加,查看或退出:
增加
输入姓名、性别、年龄,用空格作区分:
鸣人 男 18
增加成功
请输入增加,查看或退出:
查看
当前共有2名学生
姓名:小明,性别:男,年龄:20
姓名:鸣人,性别:男,年龄:18
请输入增加,查看或退出:      
退出

练习

1.甲方的需求是无止尽的,完善上面的程序!

  • 增加删除功能
  • 增加按名字搜索功能

解析

1.甲方的需求是无止尽的,完善上面的程序!

  • 增加删除功能
  • 增加按名字搜索功能
class OpDel(Op):
    action = '删除'

    @staticmethod
    def handle(data):
        inp = input('输入要删除的姓名:\n')
        for student in data:
            if student.name == inp:
                data.remove(student)
                print('删除了:%s' % student)


class OpSearch(Op):
    action = '搜索'

    @staticmethod
    def handle(data):
        inp = input('输入要搜索的姓名:\n')
        for student in data:
            if inp in student.name:
                print('搜索到:%s' % student)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,367评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,959评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,750评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,226评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,252评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,975评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,592评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,497评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,027评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,147评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,274评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,953评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,623评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,143评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,260评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,607评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,271评论 2 358

推荐阅读更多精彩内容