首页 > 其他 > 详细

一个简单的多用户交互系统的实现

时间:2018-05-13 14:47:45      阅读:180      评论:0      收藏:0      [点我收藏+]

需求如下:创建管理员、教师、学员这三个视图,实现一个简单的课程操作交互

具体实现如下:

Homework:

├─bin
│──────start.py #程序的入口

├─conf
│──────config.py #程序用到的文件的路径以及其他关系映射信息

├─core #
│──────logger.py#记录日志的逻辑
│──────main.py#实现三类用户的登陆逻辑,并利用反射调用不同类的具体方法
│──────manager.py#实现了管理员类的各个功能
│──────my_pickle.py#实现了将不同对象dump、load进文件的方法以及修改已经被dump的文件的方法
│──────other_logics.py#其他额外功能的逻辑
│──────school.py#里面的classes类用来创建与班级名相同名字的文件
│──────student.py#实现学生类的功能逻辑
│──────teacher.py#实现讲师类的功能逻辑

└─db
│──classes_obj#存放各个班级对象的信息
│──logs.log#存放日志信息
│──teacher_obj#存放讲师对象信息
│──userinfo#存放登陆用户信息

└─studentinfo#里面的文件是与班级同名的文件,各个文件里面存的是相应班级里的学员信息
│────────python_s9

  代码如下:

技术分享图片
from os import getcwd,path
from sys import path as sys_path
sys_path.insert(0,path.dirname(getcwd()))

from core import main


if __name__ == __main__:
    main.main()
start.py
技术分享图片
import os

PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
#userinfo文件的路径
USERINFO = os.path.join(PATH,db,userinfo)
#schoolinfo的路径
SCHOOLINFO = os.path.join(PATH,db,school_obj)
#teacher_obj的路径
TEACHER_OBJ = os.path.join(PATH,db,teacher_obj)
#classes_obj的路径
CLASSES_OBJ = os.path.join(PATH,db,classes_obj)
#course_obj的路径
COURSE_OBJ = os.path.join(PATH,db,course_obj)
#studentinfo的路径
STUDENTINFO = os.path.join(PATH,db,studentinfo)
#日志文件的路径
LOGGER = os.path.join(PATH,db,logs.log)
#用户选择视图输入项与身份信息的键值对
USER_DICT = {1:Manager,2:Teacher,3:Student}
#学校与课程对应关系字典
school_class = {Beijing:[python,linux],Shanghai:[go]}
config.py
技术分享图片
import logging
from conf import config

def logger_file():
    #生成logger对象
    whw_logger = logging.getLogger(logs.log)
    whw_logger.setLevel(logging.INFO)
    #生成handler对象
    whw_fh = logging.FileHandler(config.LOGGER)
    whw_fh.setLevel(logging.INFO)
    #生成Formatter对象
    file_formatter = logging.Formatter( %(asctime)s - %(name)s - %(levelname)s - %(message)s )
    #把formatter对象绑定到handler对象中
    whw_fh.setFormatter(file_formatter)
    # 把handler对象绑定到logger对象中
    whw_logger.addHandler(whw_fh)

    return whw_logger

def write_log(msg):
    log_obj = logger_file()
    log_obj.info(msg)
    log_obj.handlers.pop()
logger.py
技术分享图片
import sys
import os
from core.manager import Manager
from core.teacher import Teacher
from core.student import Student
from conf import config
from core import my_pickle
from .other_logics import file_name,show_classes,show_student_score


def login():
    ‘‘‘
    登录函数,应该先到conf.config中先读取userinfo的文件路径。
    再读取userinfo文件中的信息,对用户名与密码进行查验
    登陆成功后查看这个人的身份来确定进入哪一个视图
    :return:
    ‘‘‘
    while 1:
        print( \033[1;32m请选择用户视图:\n\033[0m,
               1:管理员视图\n,
               2:讲师视图\n,
               3:学生视图\n
        )

        choice = input(请选择相应视图的编号:)
        if not choice.isdigit() or int(choice)<=0 or int(choice)>3:
            print(\033[1;31m请输入正确的编号!\033[0m)
            continue

        else:
            username = input(用户名:)
            password = input(密 码:)
            user_identity = config.USER_DICT[choice]
            #打开userinfo文件...
            with open(config.USERINFO,r,encoding=utf-8) as f:
                for line in f:
                    user_name,pass_word,identity = line.strip().split(|)
                    #必须是用户名 密码  身份 三个全部一致才能登陆成功
                    if user_name == username and password == pass_word and user_identity == identity:
                        print(\033[1;32m%s 用户 %s 登陆成功!\033[0m % (user_identity,username))
                        #以字典形式返回用户名 身份
                        return {username:username,identity:identity}
                else:
                    print(\033[1;31m抱歉,输入有误,登陆失败!\033[0m)


def main():
    ‘‘‘
    打印欢迎信息
    调用login()——得到一个返回值:用户的姓名与身份
    打印用户身份的功能菜单
    如果用户想要调用任何方法,应该通过角色的对象调用,跳转到对应对象的方法里
    :return:
    ‘‘‘
    print(\033[0;35m欢迎进入学生选课系统!\033[0m)
    ret = login()
    if ret:
        while 1:
            #管理员登陆
            if ret[identity] == Manager:
                print(\033[0;32m******************\033[0m)
                role_class = getattr(sys.modules[__name__],ret[identity])
                #将类实例化成相应的对象
                obj = role_class(ret[username])

                while 1:
                    print(\033[0;32m******************\033[0m)
                    for i,v in enumerate(role_class.menu,1):
                        print(i,v[0])
                    #避免输入不合法,利用异常处理

                    choice = input(\033[0;32m请输入您要进行的操作编号:\033[0m)
                    if not choice.isdigit():
                        print(\033[1;31m请输入数字!\033[0m)
                        break
                    choice_int = int(choice)
                    if choice_int < 1 or choice_int > 9:
                        print(\033[1;31m抱歉,请输入正确的编号!\033[0m)
                        break
                    ##进行第二次的反射,后面加了括号直接执行了
                    getattr(obj,role_class.menu[choice_int-1][1])()
            #讲师登陆
            if ret[identity] == Teacher:
                print(\033[0;32m******************\033[0m)
                global teacher_school
                #反射:从本模块找到Teacher类
                teacher_class = getattr(sys.modules[__name__],ret[identity])
                pk_teacher = my_pickle.MyPickle(config.TEACHER_OBJ)
                ob_teacher = pk_teacher.loaditer()
                for i in ob_teacher:
                    if i.name == ret[username]:
                        teacher_school = i.school
                #利用找到的Teacher类与用户输入的name、school实例化讲师对象
                teacher_obj = teacher_class(ret[username],teacher_school)
                while 1:
                    print(\033[0;32m******************\033[0m)
                    for i,v in enumerate(teacher_class.menu,1):
                        print(i,v[0])
                    choice = input(\033[0;32m请输入您要进行的操作编号:\033[0m)
                    if choice.isdigit() and  0 < int(choice) < 5:
                        choice_int = int(choice)
                        #第二次反射,后面加了括号,直接执行就行
                        getattr(teacher_obj,teacher_class.menu[choice_int-1][1])()
                    else:
                        print(\033[1;31m抱歉,请输入正确的编号!\033[0m)
            #学生登录——需要输入班级
            if ret[identity] == Student:
                global stu_status
                stu_status = False
                global stu_class
                print(\033[0;32m******************\033[0m)
                class_input = input(请输入您所在的班级:).strip()
                #判断输入的班级是否存在
                if class_input not in file_name(config.STUDENTINFO):
                    print(\033[1;31m抱歉,请输入正确的班级!\033[0m)

                else:
                    #判断输入的班级有没有登陆的学生name
                    pk_student = my_pickle.MyPickle(os.path.join(config.STUDENTINFO,class_input))
                    obj_student = pk_student.loaditer()
                    for i in obj_student:
                        #找到了这个学生对象
                        if i.name == ret[username]:
                            #将这个班级赋值给global变量stu_class
                            stu_class = i.clas
                            stu_status = True
                    #说明成功找到了该学生的对象
                    if stu_status == True:
                        # 第一次反射
                        student_class = getattr(sys.modules[__name__], ret[identity])
                        #实例化
                        student_obj = student_class(ret[username],stu_class)
                        while 1:
                            print(\033[0;32m******************\033[0m)
                            for i,v in enumerate(student_obj.menu,1):
                                print(i,v[0])
                            choice = input(请输入您要进行的操作编号:)
                            if choice.isdigit() and ( 0 < int(choice) < 3):
                                if choice == 1:
                                    show_student_score(ret[username],class_input)
                                elif choice == 2:
                                    exit()
                            else:
                                print(\033[1;31m请输入正确的操作编号!\033[0m)
                    else:
                        print(\033[1;31m抱歉您不在这个班级!\033[0m)
        else:
            print(\033[1;31m请输入正确的用户编号\033[0m)
main.py
技术分享图片
#首先,以管理员的身份登录
#登录后 应该实例化一个对应身份的对象manager_obj = manager(name)
#管理员对象可以调用所有的方法
from conf import config
from core import teacher
from core import my_pickle
from core import student
from core import school
from .other_logics import file_name
from .logger import logger_file
from .logger import write_log
import os


#管理员类
class Manager:
    menu =[
        (创建讲师账号,create_teacher),(创建学生账号,create_student),
        (创建班级, create_classes), (查看学校,show_school),
        (查看课程,show_courses),(查看讲师,show_teachers),
        (查看班级,show_classes),(为班级指定老师,bound_class_teacher),
        (退出,exit)
          ]



    def __init__(self,name):
        self.name = name
        #相当于拿到了一个对象,这个对象里面只存了文件的名字
        self.teacher_pickle_obj = my_pickle.MyPickle(config.TEACHER_OBJ)  #拿到 mypickle_obj
        self.school_pickle_obj = my_pickle.MyPickle(config.SCHOOLINFO)
        self.classes_pickle_obj = my_pickle.MyPickle(config.CLASSES_OBJ)
        self.course_pickle_obj = my_pickle.MyPickle(config.COURSE_OBJ)

    def exit(self):
        exit()

    #往文件里面添加内容的时候写成统一的方法
    #因为它既没有引用类的属性,也没有引用对象的属性,所以把它做成非绑定方法
    @staticmethod
    def userinfo_handler(content):
        with open(config.USERINFO,a) as f:
            f.write(\n%s % content)


    def show(self,pickle_obj):
        #反射
        pick_obj = getattr(self,pickle_obj)
        #执行一个生成器函数就拿到一个生成器对象,这里拿到的每一个值,都是生成器返回的对象
        load_g = pick_obj.loaditer()
        for course_obj in load_g:
            for i in course_obj.__dict__:####
                print(%s: %s%(i,course_obj.__dict__[i]))
            print(* * 20)

    def show_school(self):
        print(校区信息如下:)
        for i,v in enumerate(config.school_class,1):
            print(%s: %s% (i,v))

    def show_teachers(self):
        self.show(teacher_pickle_obj)

    def show_courses(self):
        print(课程信息如下:)
        for i,v in enumerate(config.school_class):
            print(学校:%s-->课程:%s % (v,config.school_class[v]))

    def show_classes(self):
        self.show(classes_pickle_obj)


    def create_teacher(self):
        l = []
        with open(config.USERINFO,r) as f:
            for line in f:
                username,v,b = line.strip().split(|)
                l.append(username)
        teacher_name = input(请输入老师的姓名:)
        if teacher_name in l:
            print(\033[1;31m该讲师已经存在!\033[0m)
            return
        teacher_pass = input(请输入老师的密码:)
        self.show_school()
        teacher_school = input(请输入所属的学校:(Beijing|Shanghai))
        #存入文件
        content = %s|%s|Teacher % (teacher_name,teacher_pass)
        Manager.userinfo_handler(content)
        #根据输入的姓名与学校值实例化一个老师对象
        teacher1 = teacher.Teacher(teacher_name,teacher_school)###实例化
        self.teacher_pickle_obj.dump(teacher1)
        print(\033[0;32m讲师创建成功!\033[0m)
        write_log(创建了讲师:%s % teacher_name)


    def create_classes(self):
        #注意,新建的班级名字不能是已经存在的
        classes_names = file_name(config.STUDENTINFO)
        print(\033[0;32m已经存在的班级如下:\033[0m)
        for i,v in enumerate(classes_names,1):
            print(%s: %s % (i,v))
        class_name = input(请输入您要新建的班级名称:)
        if class_name in classes_names:
            print(\033[1;31m该班级已经存在!\033[0m)
            return
        school_name = input(请输入所属的学校:(Beijing|Shanghai))
        if school_name not in Beijing|Shanghai.split(|):
            print(\033[1;31m请输入正确的学校!\033[0m)
            return
        course_name = input(请输入课程名称:(python|linux|go))
        if course_name not in python|linux|go.split(|):
            print(\033[1;31m请输入正确的课程!\033[0m)
            return
        #判断 Beijing只能有python与linux,Shanghai只能有go:
        if (school_name == Beijing and (course_name ==python or course_name == linux)) or (school_name == Shanghai and course_name == go):
            #如果符合条件的话新建一个路径
            student_path = os.path.join(config.STUDENTINFO,class_name)
            #利用上面的路径创建一个空文件
            open(student_path,w).close()
            class_obj = school.Classes(school_name,class_name,course_name)
            #利用pickle dump实例化的对象,这一点json做不到!
            self.classes_pickle_obj.dump(class_obj)#######
            print(课程  %s 创建成功! % course_name)
            write_log(创建了课程:%s % course_name)
        else:
            print(\033[1;31m您填写的学校与课程的关系不存在!\033[0m)
            return


    def create_student(self):
        student_name = input(请输入学生姓名:)
        student_pass = input(请输入学生密码:)
        #列举出所有存在的班级
        classes_names = file_name(config.STUDENTINFO)
        print(\033[0;32m已经存在的班级如下:\033[0m)
        for i, v in enumerate(classes_names, 1):
            print(%s: %s % (i, v))

        student_class = input(请输入学生所在的班级:)
        class_g = self.classes_pickle_obj.loaditer()
        for clas in class_g:
            #这里有既有班级名卡控,不用做判断了
            if clas.name == student_class:
                #先把用户名、密码、角色写入userinfo文件中
                content = %s|%s|Student % (student_name,student_pass)
                Manager.userinfo_handler(content)
                #实例化
                stu_obj = student.Student(student_name,clas)
                student_path = os.path.join(config.STUDENTINFO,student_class)
                my_pickle.MyPickle(student_path).dump(stu_obj)
                print(学生 %s 创建成功! % student_name)
                write_log(学生 %s 创建成功! % student_name)
                return
        else:
            print(\033[1;31m输入错误,创建学生失败!\033[0m)   #for...else 语句


    def bound_class_teacher(self):
        global a
        global status
        status = False
        #显示既有的班级
        classes_names =file_name(config.STUDENTINFO)
        print(\033[0;32m已经存在的班级如下:\033[0m)
        for i, v in enumerate(classes_names, 1):
            print(%s: %s % (i, v))
        class_name = input(请输入要指定的班级:)
        #判断一下输入的班级是否存在
        if class_name not in classes_names:
            print(\033[1;31m抱歉,没有这个班级!\033[0m)
            return
        #显示既有讲师
        print(所有讲师信息为:)
        self.show_teachers()
        teacher_name = input(请输入需要指定的讲师:)
        #利用teacher_obj文件实例化出一个可迭代的对象
        teach_g = self.teacher_pickle_obj.loaditer()
        #遍历这个可迭代的对象
        for teacher_obj in teach_g:
            # 前提是姓名是唯一的,找到了对应的老师!
            if teacher_obj.name == teacher_name:
                if class_name in teacher_obj.classes:
                    print(\033[1;31m本教师已经与该课程有了绑定关系,请勿重复绑定!\033[0m)
                    return
                #将符合要求的对象赋值给一个global变量,待后面处理
                teacher_obj.classes.append(class_name)
                a = teacher_obj
                #判断成功修改
                status = True
        #必须等遍历完文件关闭后才能再进行edit操作
        if status == True:
            file1 = my_pickle.MyPickle(config.TEACHER_OBJ)
            file1.edit(a)
            print(a.name,a.classes)
            print(绑定成功!)
            write_log(班级%s绑定了讲师:%s % (class_name,teacher_name))
            a = None
            status = False
        else:
            print(\033[1;31m录入有误,绑定失败!\033[0m)
manager.py
技术分享图片
import pickle
import os

class MyPickle:
    def __init__(self,filename):
        #只是用文件名来实例化对象,并没有打开文件
        self.filename = filename

    #每次需要dump一个文件的时候需要先打开一个文件
    def dump(self,obj):
        with open(self.filename,ab) as f:
            # 利用pickle dump实例化的对象,这一点json做不到!
            pickle.dump(obj,f)

    #每次需要load文件的时候,需要转格式
    def loaditer(self):
        with open(self.filename,rb) as f:
            while 1:
                try:
                    #不能把所有的文件都同时读出来,需要每读一个文件再做一次操作
                    obj = pickle.load(f)
                    yield obj
                except:
                    break
        def close_file():
            f.close()


    #"修改"已经被dump的文件
    def edit(self,obj):
        #利用原文件.bak这个路径名实例化一个新的对象,然后利用dump跟loaditer方法将满足条件的信息写进这个bak文件中,最后replace~~
        f_temp = MyPickle(self.filename+.bak)
        with open(self.filename,rb+) as f:
            for i in self.loaditer():
                if i.name == obj.name:
                    f_temp.dump(obj)
                else:
                    f_temp.dump(i)

        os.replace(self.filename+.bak,self.filename)
my_pickle.py
技术分享图片
import os
from conf import config
from .my_pickle import MyPickle

# 查找studentinfo文件夹下文件列表的方法
def file_name(file_dir):
    for root, dirs, files in os.walk(file_dir):
        return files


# 显示etudentinfo文件夹下所有文件名的方法
def show_classes():
    for root, dirs, files in os.walk(config.STUDENTINFO):
        for i, v in enumerate(files, 1):
            print(%s : %s % (i, v))


# 因为学生需要班级来实例化,而班级是一个个的文件,所以显示学生成绩的方法写在函数里
def show_student_score(name, file):
    class_path = os.path.join(config.STUDENTINFO, file)
    pk_stu = MyPickle(class_path)
    obj_stu = pk_stu.loaditer()
    for i in obj_stu:
        if i.name == name:
            print(%s 的成绩为:%s % (name, i.score))
            return
other_logics.py
技术分享图片
class Classes:
    def __init__(self,school,name,course):
        self.school = school
        self.name = name #班级名称,,
        self.course = course  #科目 python go linux
        #self.student_path = student_path  #学生信息文件的绝对路径
school.py
技术分享图片
class Student:
    menu = [(查看自己的成绩:,show_my_score),
            (退出,exit)
        ]

    def __init__(self,name,clas):
        self.name = name
        self.clas = clas
        self.score = ‘‘
student.py
技术分享图片
from core import my_pickle
from conf import config
import os

# class Classes:
#     def __init__(self,school_name,class_name,class_kind):
#         self.school_name = school_name #分校
#         self.class_name = class_name #班级名 python_s11
#         self.class_kind = class_kind #班级科目 python go linux
#         self.student = [‘student_obj‘]


class Course:
    def __init__(self,course_name,course_period,course_price):
        self.course_name = course_name
        self.course_period = course_period#周期
        self.course_price = course_price


class Teacher:
    menu = [
        (查看本人所授班级,show_classes),
        (查看所授班级学生,show_class_students),
        (修改学生成绩,reverse_grade),
        (退出,exit)
    ]

    def __init__(self,name,school):
        self.name = name
        self.school = school
        self.classes = []

    def exit(self):
        exit()


    def show_classes(self):
        print(\033[1;32m您所教授的班级为:\033[0m)
        global classes_list
        #利用teacher_obj文件实例化一个MyPickle对象
        teacher_file = my_pickle.MyPickle(config.TEACHER_OBJ)
        #利用loaditer得到一个可迭代的对象
        teacher_obj = teacher_file.loaditer()
        #遍历~
        for i in teacher_obj:
            #找到对应的讲师
            if i.name == self.name:
                #班级列表赋值给classes_list
                classes_list = i.classes
        #显示这个classes_list列表,就是这个老师教的班级
        for i,v in enumerate(classes_list,1):
            print(%s: %s % (i,v))
        return


    def show_class_students(self):
        clas = input(请输入您要查找学生所在的班级:).strip()
        global classes_list1
        # 利用teacher_obj文件实例化一个MyPickle对象
        teacher_file = my_pickle.MyPickle(config.TEACHER_OBJ)
        # 利用loaditer得到一个可迭代的对象
        teacher_obj = teacher_file.loaditer()
        # 遍历~
        for i in teacher_obj:
            # 找到对应的讲师
            if i.name == self.name:
                # 班级列表赋值给classes_list
                classes_list1 = i.classes
        #判断输入的班级是否在老师所教班级的列表里
        if clas in classes_list1:
            #得到这个班级文件的路径
            class_path = os.path.join(config.STUDENTINFO,clas)
            #利用这个班级文件路径再实例化一个MyPickle对象...
            pk_class = my_pickle.MyPickle(class_path)
            class_obj = pk_class.loaditer()
            for i in class_obj:
                print(学生姓名:%s;学生成绩:%s % (i.name,i.score))

        else:
            print(\033[1;31m抱歉,您没有教这个班级!\033[0m)


    def reverse_grade(self):
        self.show_classes()
        clas = input(请输入您要修改的学生所在的班级:).strip()
        global classes_list1
        global stu1
        global s_status
        s_status = False
        # 利用teacher_obj文件实例化一个MyPickle对象
        teacher_file = my_pickle.MyPickle(config.TEACHER_OBJ)
        # 利用loaditer得到一个可迭代的对象
        teacher_obj = teacher_file.loaditer()
        # 遍历~
        for i in teacher_obj:
            # 找到对应的讲师
            if i.name == self.name:
                # 班级列表赋值给classes_list
                classes_list1 = i.classes
        # 判断输入的班级是否在老师所教班级的列表里
        if clas in classes_list1:
            # 得到这个班级文件的路径
            class_path = os.path.join(config.STUDENTINFO, clas)
            # 利用这个班级文件路径再实例化一个MyPickle对象...
            pk_class = my_pickle.MyPickle(class_path)
            class_obj = pk_class.loaditer()
            choice_stu = input(请输入您要修改成绩的学生:).strip()
            score = input(请输入该学生修改后的成绩:).strip()
            for i in class_obj:
                if i.name == choice_stu:
                    i.score = score
                    #将这个学生对象赋值给global变量stu1
                    stu1 = i
                    s_status = True

        else:
            print(\033[1;31m抱歉,您没有教这个班级!\033[0m)
            return

        if s_status == True:
            stu_file = my_pickle.MyPickle(os.path.join(config.STUDENTINFO,clas))
            stu_file.edit(stu1)
            print(学生:%s;成绩:%s % (stu1.name,stu1.score))
            print(\033[1;32m修改成功!\n\033[0m)
            s_status = False
        else:
            print(\033[1;31m录入有误,操作失败!\033[0m)
teacher.py

 

演示如下:

技术分享图片

 

 

 

 

 

 

 

 

 

 

 


│────────......

 

一个简单的多用户交互系统的实现

原文:https://www.cnblogs.com/paulwhw/p/9032015.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!