需求以下:建立管理員、教師、學員這三個視圖,實現一個簡單的課程操做交互python
具體實現以下:linux
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_s9git
代碼以下:json
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()
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']}
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()
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')
#首先,以管理員的身份登陸 #登陸後 應該實例化一個對應身份的對象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')
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)
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
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 #學生信息文件的絕對路徑
class Student: menu = [('查看本身的成績:','show_my_score'), ('退出','exit') ] def __init__(self,name,clas): self.name = name self.clas = clas self.score = ''
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')
演示以下:app