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

Posted 江湖乄夜雨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一个简单的多用户交互系统的实现相关的知识,希望对你有一定的参考价值。

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

具体实现如下:

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(如何使用 xcode 将快照划分为多个片段,以便让用户与每个片段进行交互?

几个非常实用的JQuery代码片段

浏览器的多进程

简单输入输出交互。 用户输入两个数字,计算并输出两个数字之和:(尝试只用一行代码实现这个功能) 输入半径,计算圆的面积。简单输入输出交互。 用户输入两个数字,计算并输出两个数字之和:(尝试只用一行代码

十条jQuery代码片段助力Web开发效率提升

十条jQuery代码片段助力Web开发效率提升