Python语言系列-07-面向对象2





重构父类__init__方法

#!/usr/bin/env python3
# author:Alnk(李成果)
# 需求:Dog类要新增一个实例属性,但是Cat类不需要


class Animal(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def run(self):
        print('run...')

    def sleep(self):
        print('sleep...')


class Cat(Animal):
    pass


class Dog(Animal):
    def __init__(self, name, age, kind):
        super().__init__(name, age)  # 执行父类方法
        self.kind = kind


t = Dog('tom', 23, '狗子')
print(t.kind)

c = Cat("jerry", 1)
print(c.name)




封装

封装-基本概念

#!/usr/bin/env python3
# author: Alnk(李成果)

"""
封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式
好处:将变化隔离、便于使用、提高重用性、提高安全性
封装原则:将不需要对外提供的内容都隐藏起来、把属性都隐藏,提供公共方法对其访问

使用封装有好处:
    1、良好的封装能够减少耦合
    2、类内部的结构可以自由修改
    3、可以对成员进行更精确的控制
    4、隐藏信息,隐藏实现细节

用法:
    私有化变量(属性)
    私有化方法
    property属性
    classmethod方法
    staticmethod方法
"""



封装-实例私有属性

#!/usr/bin/env python3
# author: Alnk(李成果)


# 一般属性
class Student(object):

    def __init__(self, name, age):
        self.name = name  # 一般属性
        self.age = age


t = Student('tom', 24)
print(t.age)  # 可以直接在类的外面访问
print("----------------- 1 ----------------")


# 私有化属性 __变量
# 保护数据,不让类外部直接访问
class Student(object):

    def __init__(self, name, age):
        self.__name = name  # 实例私有属性:__变量
        self.__age = age

    def print_age(self):
        print('年龄:%s' % self.__age)  # 私有化属性可以在类的内部访问


t = Student('tom', 24)
# print(t.age)  # 不可以直接在类的外部访问
# print(t.__dict__["_Student__age"])  # python中还是有方法可以访问实例的私有属性的
t.print_age()
print("----------------- 2 ----------------")


# 需求:要在类的外部访问私有化属性。
# 开接口:能在外部修改类的私有属性,但是能更加精确的控制
# 好处:可以更加精确的控制数据
class Student(object):

    def __init__(self, name, age):
        self.__name = name  # 私有属性
        self.__age = age

    def get_age(self):  # 提供可读属性接口
        return self.__age

    def set_age(self, new_age):  # 提供可写属性接口
        if isinstance(new_age, int) and (0 < new_age < 120):
            self.__age = new_age
        else:
            # raise ValueError("年龄不符合条件")  # 直接让程序报错,停止程序
            print("年龄不符合条件")


t = Student('tom', 24)
# 可读接口
print(t.get_age())

# 可写接口
t.set_age(80)
print(t.get_age())
t.set_age(1000)
print(t.get_age())



封装-实例私有属性存储关系

#!/usr/bin/env python3
# author: Alnk(李成果)


# 一般属性存储关系
class Student(object):
    x = 100
    def __init__(self, name, age):
        self.name = name  # 一般属性
        self.age = age


tom = Student('tom', 24)
print(tom.name)  # tom

# __dict__ 打印tom实例对象的所有变量
print(tom.__dict__)  # {'name': 'tom', 'age': 24}

tom.sex = 'F'
print(tom.__dict__)  # {'name': 'tom', 'age': 24, 'sex': 'F'}
print("----------------- 1 ----------------")


# 实例私有属性存储关系
class Student(object):

    def __init__(self, name, age):
        self.__name = name  # 私有属性
        self.__age = age

    def get_age(self):  # 提供可读属性接口
        return self.__age

    def set_age(self, new_age):  # 提供可写属性接口
        if isinstance(new_age, int) and (0 < new_age < 120):
            self.__age = new_age
        else:
            print("年龄不符合条件")


# 1 外部可以控制私有属性,强烈不建议使用,不规范
tom = Student('tom', 24)
print(tom.__dict__)  # 私有属性  "_当前类名__私有变量":实际值  {'_Student__name': 'tom', '_Student__age': 24}
tom.sex = 'F'
print(tom.__dict__)  # {'_Student__name': 'tom', '_Student__age': 24, 'sex': 'F'}

# 直接访问私有属性
print(tom._Student__name)  # tom

# 直接修改私有属性,但是不建议这么用,不规范,私有变量不建议更改
# 结论:python的私有属性\变量并不是真正的私有属性\变量,还是有方法可以控制的。
# 但是,不建议使用,不规范
tom._Student__age = 10000
print(tom.get_age())  # 10000
print("----------------- 2 ----------------")


# 2
tom = Student('tom', 24)
# 相当于在tom的实例内存空间追加了一个变量 __age = 1000
tom.__age = 1000

print(tom.__age)  # 1000
print(tom.__dict__)  # {'_Student__name': 'tom', '_Student__age': 24, '__age': 1000}



封装-类私有属性

#!/usr/bin/env python3
# author: Alnk(李成果)
# 类属性的私有化
# 私有属性不仅适用于实例属性,也适用于类属性


# 一般类 属性\变量
class Parent(object):
    x = 100  # 一般类 属性\变量

    def f1(self):
        pass


p1 = Parent()       # 实例化
print(p1.x)         # 100
print(p1.__dict__)  # {} 这里空字典的原因是:实例空间没有实例属性

# 类对象
print(Parent.x)  # 100 类属性
print(Parent.__dict__)  # {..., 'x': 100, 'f1': <function Parent.f1 at 0x7fa1c92eca60>, ...}
print("----------------- 1 ----------------")


# 类 属性\变量 的私有化
class Parent(object):
    __x = 100

    def f1(self):
        pass


p1 = Parent()
# print(p1.__x)  # 类私有属性,外部不能直接访问
# print(Parent.__x)  # 类私有属性,外部不能直接访问
print(Parent.__dict__)  # {'_Parent__x': 100, 'f1': <function Parent.f1 at 0x7f9ed82e19d8>,}

# 可以通过这种方法访问,但是强烈建议不要这么使用
print(Parent._Parent__x)  # 100
print(Parent.__dict__["_Parent__x"])  # 100



封装-私有属性不能继承

#!/usr/bin/env python3
# author:Alnk(李成果)
# 私有属性不能继承


class A:
    __x = 100  # 类私有属性
    y = 200    # 类一般属性

    def __init__(self):
        self.__name = "alnk"
        self.age = 14


class B(A):
    z = 300


b = B()

# 类一般属性的继承
print(b.z)  # 300
print(b.y)  # 200

# 类私有属性不能继承
# print(b.__x)    # 报错 AttributeError: 'B' object has no attribute '__x'

# 当然有其他方法也可以访问
print(b._A__x)    # 100 不建议这么做
print("-------------- 1 ---------------------")


# 实例一般属性的继承
print(b.age)  # 14

# 实例私有属性不能继承
# print(b.__name)  # 报错 AttributeError: 'B' object has no attribute '__name'

# 当然有其他方法也可以访问
print(b._A__name)  # alnk 不建议这么做



封装-下划线

#!/usr/bin/env python3
# author: Alnk(李成果)

"""
单下划线、双下划线、头尾双下划线说明
__foo__: 定义的是特殊方法,一般是系统定义名字 ,类似 __init__() 之类的
_foo:    以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问(约定成俗,不限语法)
__foo:   双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问了

变量      public          公共的
_变量     protected       受保护的
__变量    private         私有的
"""


class A(object):
    _x = 10
    __y = 20
    z = 30


a = A()

# 10 约定成俗,不限语法
print(a._x)     # 10
print(a.z)      # 30

# print(a.__y)    # 报错
print(a._A__y)  # 20
print(a.__dict__)  # 实例空间变量 {}
print(A.__dict__)  # 类空间变量 {'_x': 10, '_A__y': 20, 'z': 30}
print(A.__dict__["_A__y"])  # 20



封装-私有方法不能继承

#!/usr/bin/env python3
# author:Alnk(李成果)
# 在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
# 私有方法不能继承


# 正常情况
class A(object):
    def fa(self):
        print('from A')

    def test(self):
        self.fa()


class B(A):
    pass


b = B()
b.fa()    # from A
b.test()  # from A
print("---------------- 1 -----------------------")


# 把 fa 定义为私有的,即 __fa
class A(object):
    def __fa(self):  # 在定义的时候就变形为 _A__fa
        print('from A')

    def test(self):
        self.__fa()  # 只会以自己所在的类为准,基调用 _A__fa


class B(A):
    # def __fa(self):
    #     print('from B')
    pass


b = B()
b.test()  # from A

# b.__fa()  # 报错 AttributeError: 'B' object has no attribute '__fa'
b._A__fa()  # from A



封装-property属性

#!/usr/bin/env python3
# author:Alnk(李成果)

# 什么是特性property
# property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
# 把一个方法属性化


# 为什么要用property?
# 将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,
# 这种特性的使用方式遵循了统一访问的原则在C++里一般会将所有的数据都设置为私有的,
# 然后提供set和get方法(接口)去设置和获取,在python中通过property方法可以实现


class People(object):
    def __init__(self, name, weight, height):
        self.name = name
        self.wight = weight
        self.height = height

    @property  # 改变一个方法的调用方式
    def bmi(self):
        return self.wight / (self.height**2)

    def test(self):
        print("in test")


p1 = People('tom', 75, 1.85)

p1.test()  # 正常的调用一个方法

print(p1.bmi)  # 改变一个方法的调用方式



封装-classmethod方法

#!/usr/bin/env python3
# author:Alnk(李成果)
# classmethod 修饰符对应的函数不需要实例化,不需要 self 参数
# 但第一个参数需要是表示自身类的 cls 参数,可以来调用类的属性,类的方法,实例化对象等


class Student(object):
    school = '清华大学'

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def run(self):
        print('%s is running... ' % self.name)

    @classmethod  # 类方法
    def foo(cls):
        print(cls)                     # 和 Student 的内存地址相同
        print('cls', id(cls))          # 是同一个内存地址
        print("student", id(Student))  # 是同一个内存地址
        print('学校名称:%s' % cls.school)


# 实例方法是由实例对象调用的,不能直接由类调用
tom = Student('tom', 23)
jerry = Student('jerry', 24)
tom.run()
jerry.run()
# Student.run()  # TypeError: run() missing 1 required positional argument: 'self'
print("------------- 1 -------------------")


# 类方法,可以直接由类调用
Student.foo()
print("------------- 2 -------------------")

# 当然,实例也可以调用类方法
tom.foo()



封装-staticmethod方法

#!/usr/bin/env python3
# author: Alnk(李成果)

# 实例方法:             涉及到实例变量的时候使用
# 类方法classmethod:    涉及到类变量的时候使用
# 静态方法staticmethod: 不涉及到类变量和实例变量的时候使用


class Student(object):
    school = '清华大学'

    def __init__(self, name, age):
        self.name = name
        self.age = age

    # 一般方法
    def run(self):
        print('%s is running... ' % self.name)

    # 类方法
    @classmethod
    def foo(cls):
        print('学校名称:%s' % cls.school)

    # 静态方法
    @staticmethod
    def calculation(x, y):  # 没有self了
        return x * y


tom = Student('tom', 26)

# 一 调用静态方法
# 1,实例调用静态方法
ret = tom.calculation(2, 8)
print(ret)

# 2,类调用静态方法
ret1 = Student.calculation(3, 6)  # 不需要传入self了
print(ret1)
print("---------------- 1 ----------------------")

# 二 调用类方法
Student.foo()
tom.foo()
print("---------------- 1 ----------------------")

# 三 调用一般方法
tom.run()
# Student.run()  # TypeError: run() missing 1 required positional argument: 'self'




归一化设计

#!/usr/bin/env python3
# author: Alnk(李成果)

# 归一化设计
# 做成一个接口
lis = [1, 2, 3]
dic = {1: 2, 3: 4, 5: 6}
s = 'hello'

# 需求
# 求一个序列对象的长度
print(lis.__len__())
print(dic.__len__())
print(s.__len__())
print("---------------- 1 ------------------------")

# 归一接口:len()
print(len(lis))
print(len(dic))
print(len(s))
print("---------------- 2 ------------------------")


# 支付接口归一化
class Payment(object):
    def __init__(self, name, money):
        self.name = name
        self.money = money


class AliPay(Payment):
    def pay(self):
        print('%s通过支付宝消费了%s元' % (self.name, self.money))


class WeChatPay(Payment):
    def pay(self):
        print('%s通过微信消费了%s元' % (self.name, self.money))


def pay_func(pay_obj):  # 接口归一
    pay_obj.pay()


a = AliPay('tom', 100)
w = WeChatPay('jerry', 200)

# 调用归一接口
pay_func(a)
pay_func(w)
print("---------------- 3 ------------------------")

# 支付接口归一化,规范的写法
"""
规范化方法
支付宝 微信 银行卡 nfc支付
同事协作之间的代码规范问题

规定: Payment 就是一个规范类,这个类存在的意义不在于实现实际的功能,而是为了约束所有的子类必须实现pay的方法
Payment : 抽象类
    pay = Payment() # 抽象类: 不能实例化
    抽象类主要就是作为基类/父类,来约束子类中必须实现的某些方法
    抽象类的特点:
        必须在类定义的时候指定 metaclass = ABCMeta
        必须在要约束的方法上方加上 @abstractmethod 方法
"""

from abc import ABCMeta, abstractmethod  # (抽象方法)


class Payment(metaclass=ABCMeta):  # metaclass 元类  metaclass = ABCMeta表示Payment类是一个规范类
    def __init__(self, name, money):
        self.name = name
        self.money = money

    @abstractmethod  # 当子类继承的时候,必须重构pay方法,不然在子类实例化的时候就报错
    def pay(self):
        pass


class AliPay(Payment):
    def pay(self):
        print('%s通过支付宝消费了%s元' % (self.name, self.money))


class WeChatPay(Payment):
    def pay(self):
        print('%s通过微信消费了%s元' % (self.name, self.money))


def pay_func(pay_obj):  # 接口归一
    pay_obj.pay()


a = AliPay('tom', 2000)
w = WeChatPay('jerry', 4000)

# 调用归一接口
pay_func(a)
pay_func(w)




多态

#!/usr/bin/env python3
# author: Alnk(李成果)
# 多态
# 第一种解释
# 多态:指的是一类事物有多种形态
# 动物有多种形态:人,狗,猪
import abc


class Animal(metaclass=abc.ABCMeta):  # 同一类事物:动物
    @abc.abstractmethod
    def talk(self):
        pass


class People(Animal):  # 动物形态之一:人
    def talk(self):
        print('say hello')


class Dog(Animal):     # 动物的形态之二:狗
    def talk(self):
        print('say 旺旺旺')


class Pig(Animal):     # 动物的形态之三:猪
    def talk(self):
        print('say 嗷嗷嗷')


# 文件有多种形态:文本文件,可执行文件
class File(metaclass=abc.ABCMeta):  # 同一类事物:文件
    @abc.abstractmethod
    def click(self):
        pass


class Text(File):                   # 文件的形态之一:文本文件
    def click(self):
        print('open file')


class ExeFile(File):                # 文件的形态之二:可执行文件
    def click(self):
        print('execute file')


# 什么是多态动态绑定(在继承的背景下使用时,有时也称为多态性)
# 多态性是指在不考虑实例类型的情况下使用实例
# 在面向对象方法中一般是这样表述多态性
# 向不同的对象发送同一条消息
# (obj.func(): 是调用了obj的方法func,又称为向obj发送了一条消息func),不同的对象在接收时会产生不同的行为(即方法)
# 也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数
# 比如:老师.下课铃响了(),学生.下课铃响了(),老师执行的是下班操作,学生执行的是放学操作,虽然二者消息一样,但是执行的效果不同

# 多态性
peo = People()
dog = Dog()
pig = Pig()

# peo、dog、pig都是动物,只要是动物肯定有talk方法
# 于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
peo.talk()
dog.talk()
pig.talk()
print("--------------------------- 1 ---------------------------------")


# 更进一步,我们可以定义一个统一的接口来使用
def func(obj):
    obj.talk()


func(peo)
func(dog)
func(pig)
print("--------------------------- 2 ---------------------------------")


# 多态
# 第二种解释
# from abc import ABCMeta, abstractmethod
#
#
# class Payment(metaclass=ABCMeta):
#     def __init__(self, name, money):
#         self.money = money
#         self.name = name
#
#     @abstractmethod
#     def pay(self):
#         pass
#
#
# class AliPay(Payment):
#     def pay(self):
#         # 支付宝提供了一个网络上的联系渠道
#         print('%s通过支付宝消费了%s元' % (self.name, self.money))
#
#
# class WeChatPay(Payment):
#     def pay(self):
#         # 支付宝提供了一个网络上的联系渠道
#         print('%s通过微信消费了%s元' % (self.name, self.money))
#
#
# class ApplePay(Payment):
#     def pay(self):
#         print('%s通过apple消费了%s元' % (self.name, self.money))
#
#
# al = AliPay("tom", 100)
# w = WeChatPay('tom', 200)
# ap = ApplePay("jerry", 1000)
#
#
# def pay_func(pay_obj):
#     pay_obj.pay()
#


# pay_func(al)
# pay_func(w)
# pay_func(ap)


# 多态的概念
# 要理解什么是多态,我们首先要对数据类型再作一点说明
# 当我们定义一个class的时候,我们实际上就定义了一种数据类型
# 我们定义的数据类型和Python自带的数据类型,比如str、list、dict没什么两样

# a = list()    # a是list类型
# b = Animal()  # b是Animal类型
# c = Dog()     # c是Dog类型

# 判断一个变量是否是某个类型可以用isinstance()判断:
# >>> isinstance(a, list)
# True
# >>> isinstance(b, Animal)
# True
# >>> isinstance(c, Dog)
# True 
# 看来a、b、c确实对应着list、Animal、Dog这3种类型。
# 但是等等,试试:
# >>> isinstance(c, Animal)
# True
# 看来c不仅仅是Dog,c还是Animal!
# 不过仔细想想,这是有道理的,因为Dog是从Animal继承下来的,
# 当我们创建了一个Dog的实例c时,我们认为c的数据类型是Dog没错,但c同时也是Animal也没错,Dog本来就是Animal的一种!
# 所以,在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类
# 但是,反过来就不行:
# >>> b = Animal()
# >>> isinstance(b, Dog)
# False
# Dog可以看成Animal,但Animal不可以看成Dog
# 所以,上面的支付的例子,如果我们再定义一个ApplePay类型,也从Payment类派生:
# class ApplePay(Payment):
#     def pay(self):
#        print('%s通过苹果支付消费了%s元'%(self.name,self.money))
#
# ap=ApplePay("lisa",800)

# 你会发现,新增一个Payment的子类,不必对pay()做任何修改,
# 实际上,任何依赖Payment作为参数的函数或者方法都可以不加修改地正常运行,原因就在于多态。

# 多态的好处就是,当我们需要传入AliPay、WeChatPay、ApplePay……时,
# 我们只需要接收Payment类型就可以了,因为AliPay、WeChatPay、ApplePay……都是Payment类型,
# 然后,按照Payment类型进行操作即可。由于Payment类型有pay()方法,
# 因此,传入的任意类型,只要是Payment类或者子类,就会自动调用实际类型的pay()方法,这就是多态的意思

# 对于一个变量,我们只需要知道它是Payment类型,无需确切地知道它的子类型,
# 就可以放心地调用pay()方法,而具体调用的pay()方法是作用在AliPay、WeChatPay、ApplePay哪个类对象上,
# 由运行时该对象的确切类型决定,这就是多态真正的威力:调用方只管调用,不管细节,
# 而当我们新增一种Payment的子类时,只要确保pay()方法编写正确,不用管原来的代码是如何调用的
# 这就是著名的“开闭”原则:
# 对扩展开放:允许新增Payment子类;
# 对修改封闭:不需要修改依赖Payment类型的pay()等函数




鸭子类型

#!/usr/bin/env python3
# author: Alnk(李成果)
# 鸭子类型
from abc import ABCMeta, abstractmethod


class Payment(metaclass=ABCMeta):  # Payment看做是一只鸭子
    def __init__(self, name, money):
        self.name = name
        self.money = money

    @abstractmethod
    def pay(self):
        pass


class AliPay(Payment):
    def pay(self):
        print('%s通过支付宝消费了%s元' % (self.name, self.money))


class WeChatPay(Payment):
    def pay(self):
        print('%s通过微信消费了%s元' % (self.name, self.money))


class CardPay(object):    # 像鸭子
    def __init__(self, name, money):
        self.money = money
        self.name = name

    def pay(self):
        print('%s通过银联卡支付消费了%s元' % (self.name, self.money))


def pay_func(pay_obj):  # 传入的值只要像鸭子就行
    pay_obj.pay()


a = AliPay('tom', 100)
w = WeChatPay('jerry', 200)
pay_func(a)
pay_func(w)

# 调用鸭子的接口
cp = CardPay("lisa", 1000)
pay_func(cp)


# 对于静态语言(例如Java)来说,如果需要传入Payment类型,则传入的对象必须是Payment类型或者它的子类,
# 否则,将无法调用pay()方法。

# 对于Python这样的动态语言来说,则不一定需要传入Payment类型。我们只需要保证传入的对象有一个pay()方法就可以了

# 这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,
# 那它就可以被看做是鸭子




练习题

需求

需求:
    从“学生选课系统” 这几个字就可以看出来,我们最核心的功能其实只有 选课

    角色:
        学生、管理员、讲师

    功能:
        登陆 : 管理员和学生都可以登陆,且登陆之后可以自动区分身份
        选课 : 学生可以自由的为自己选择课程
        创建用户 : 选课系统是面向本校学生的,因此所有的用户都应该由管理员完成
        查看选课情况 :每个学生可以查看自己的选课情况,而管理员应该可以查看所有学生的信息

    工作流程:
        登陆 :用户输入用户名和密码
        判断身份 :在登陆成果的时候应该可以直接判断出用户的身份 是学生、讲师还是管理员

        学生用户 :对于学生用户来说,登陆的工作几乎不变
            1、查看所有课程
            2、选择课程
            3、查看所选课程
            4、退出程序

        管理员用户:管理员用户也可以做更多的事情
            1、创建课程
            2、创建学生学生账号
            3、查看所有课程
            4、查看所有学生
            5、查看所有学生的选课情况
            6、创建讲师
            7、为讲师指定班级
            8、创建班级
            9、为学生指定班级
            10、退出程序

        讲师用户 :对于讲师用户来说,可以完成的功能如下
            1、查看所有课程
            2、查看所教班级
            3、查看班级中的学生
            4、退出程序



逻辑图



course_system.py

#!/usr/bin/env python3
# author: Alnk(李成果)
import sys
import os
import json


class Base:  # 基础类
    def __read_dic__(self, filename):  # 读取json格式的文件
        with open(filename, encoding='utf', mode='r') as f:
            info_dic = json.load(f)
            return info_dic

    def __wirte_dic__(self, filename, info_dic):  # 写入json类型文件
        with open(filename, encoding='utf', mode='w') as f:
            json.dump(info_dic, f)
        return True

    def __read_file__(self, filename):  # 读取普通文件
        file_list = []
        with open(filename, encoding='utf', mode='r') as f:
            for line in f:
                file_list.append(line.strip())
        return file_list

    def __write_file__(self, filename, info):  # 写入普通文件
        with open(filename, encoding='utf', mode='a') as f:
            f.write('%s\n' % info)
        return True


class Parent(Base):  # 父类
    def show_courses(self):  # 查看所有课程
        courses_list = self.__read_file__('course_list')
        print('\n所有课程:%s' % courses_list)
        return courses_list

    def exit(self):  # 退出
        exit()


class Student(Parent):  # 学生类
    option_lis = [('show_courses', '查看所有课程'),
                  ('select_course', '选择课程'),
                  ('check_selected_course', '查看已选课程'),
                  ('exit', '退出'),
                  ]

    def __init__(self, name):
        self.name = name

    def select_course(self):  # 选择课程
        course_list = self.show_courses()  # 查看所有课程
        select_course = input('输入课程名称>>')
        if select_course in course_list:
            stu_dic = self.__read_dic__(self.name)  # 读取学生个人详细信息
            stu_dic["select_course"].append(select_course)
            self.__wirte_dic__(self.name, stu_dic)  # 写入学生个人信息
        else:
            print('课程不存在')

    def check_selected_course(self):  # 查看已选课程
        stu_dic = self.__read_dic__(self.name)  # 读取学生个人信息
        print('已选课程:', stu_dic["select_course"])


class Manage(Parent):  # 管理员类
    option_lis = [
        ('create_course', '创建课程'),
        ('create_stu', '创建学生'),
        ('show_courses', '查看所有课程'),
        ('show_students', '查看所有学生'),
        ('show_students_courses', '查看所有学生的选课情况'),
        ('create_teacher', '创建讲师'),
        ('create_class', '创建班级'),
        ('appoint_tearcher_class', '为讲师指定班级'),
        ('appoint_stu_class', '为学生指定班级'),
        ('exit', '退出'),
    ]

    def __init__(self, name):
        self.name = name

    def create_course(self):  # 创建课程
        course_name = input('课程名称>>>').strip()
        self.__write_file__('course_list', course_name)  # 写入课程文件
        print('\n%s课程创建成功\n' % course_name)

    def create_stu(self):  # 创建学生
        stu_name = input('学生账号>>>')
        stu_pwd = input('密码>>>')
        stu_info_dic = {'username': stu_name, 'passwd': stu_pwd, 'id': 'Student', 'select_course': [], 'class': []}
        self.__wirte_dic__(stu_name, stu_info_dic)  # 写入学生详细信息
        self.__write_file__('students_list', stu_name)  # 学生总列表
        print('\n学生%s创建成功\n' % stu_name)

    def show_students(self):  # 查看所有学生
        students_list = self.__read_file__('students_list')  # 读取学生总列表文件
        print('\n所有的学生:%s' % students_list)

    def show_students_courses(self):  # 查看所有学生的选课情况
        stu_lis = self.__read_file__('students_list')  # 读取学生总列表文件
        for i in stu_lis:
            stu_dic = self.__read_dic__(i)  # 学生个人详细信息
            print('%s 选课情况:%s' % (i, stu_dic['select_course']))

    def create_teacher(self):  # 创建讲师
        t_name = input('讲师账号>>>')
        t_pwd = input('密码>>>')
        t_dic = {"username": t_name, "passwd": t_pwd, "id": "Teacher", "class": []}
        self.__wirte_dic__(t_name, t_dic)  # 写入老师详细信息
        self.__write_file__('teacher_list', t_name)  # 写入老师总文件
        print('讲师 %s 创建成功' % t_name)

    def appoint_tearcher_class(self):  # 为讲师指定班级
        teacher_list = self.__read_file__('teacher_list')  # 读取老师总文件
        class_list = self.__read_file__('class_list')  # 读取班级总文件
        print('所有老师:%s' % teacher_list)
        t_name = input('讲师名称>>>').strip()
        print('所有班级:%s' % class_list)
        c_name = input('班级名称>>>').strip()
        if t_name in teacher_list and c_name in class_list:
            teacher_dic = self.__read_dic__(t_name)  # 读取老师个人信息
            teacher_dic['class'].append(c_name)
            self.__wirte_dic__(t_name, teacher_dic)  # 写入老师个人信息
            print('已为讲师 %s 指定班级 %s' % (t_name, c_name))
        else:
            print('讲师或班级不存在')

    def create_class(self):  # 创建班级
        class_name = input('创建班级名称:')
        self.__write_file__('class_list', class_name)  # 写入班级总文件
        print('%s 班级创建成功' % class_name)

    def appoint_stu_class(self):  # 为学生指定班级
        stu_list = self.__read_file__('students_list')  # 读取学生总列表文件
        class_list = self.__read_file__('class_list')  # 读取班级总文件
        print('所有学生:%s' % stu_list)
        stu_name = input('学生名称>>>')
        print('所有班级:%s' % class_list)
        class_name = input('班级名称>>>')
        if stu_name in stu_list and class_name in class_list:
            self.__write_file__(class_name, stu_name)  # 写入班级文件
            stu_dic = self.__read_dic__(stu_name)  # 读取学生信息
            stu_dic['class'].append(class_name)
            self.__wirte_dic__(stu_name, stu_dic)
            print('为学生 %s 指定班级 %s 成功' % (stu_name, class_name))
        else:
            print('班级或学生不存在')


class Teacher(Parent):  # 讲师类
    option_lis = [('show_courses', '查看所有课程'),
                  ('show_class', '查看所教班级'),
                  ('show_class_students', '查看班级中的学生'),
                  ('exit', '退出'),
                  ]

    def __init__(self, name):
        self.name = name

    def show_class(self):  # 查看所教班级
        tearcher_dic = self.__read_dic__(self.name)
        print('所教班级%s' % tearcher_dic['class'])

    def show_class_students(self):  # 查看班级中的学生
        tearcher_dic = self.__read_dic__(self.name)
        print('%s 班级中的学生:' % tearcher_dic['class'])
        for i in tearcher_dic['class']:
            stu_list = self.__read_file__(i)
            print(stu_list)


def login():  # 登录函数
    name = input('username>>>:')
    pwd = input('password>>>:')
    if os.path.isfile(name):
        with open(name, encoding='utf-8', mode='r') as f:
            user_dic = json.load(f)
        if user_dic['passwd'] == pwd:
            return {'result': True, 'name': name, 'id': user_dic['id']}
        else:
            return {'result': False, 'name': name}
    else:
        return {'result': False, 'name': name}


def main():
    ret = login()
    if ret['result']:
        print('登录成功')
        if hasattr(sys.modules[__name__], ret['id']):
            cls = getattr(sys.modules[__name__], ret['id'])  # 类
            obj = cls(ret['name'])  # 实例化
            while 1:
                print('\n')
                for k, i in enumerate(cls.option_lis, 1):
                    print(k, i[1])
                try:
                    choice = int(input(">>>:"))
                except ValueError:
                    print("\n请输入编号")
                    continue
                func_str = cls.option_lis[choice - 1][0]
                if hasattr(obj, func_str):
                    getattr(obj, func_str)()
    else:
        print('登录失败')


if __name__ == '__main__':
    main()


admin

{"username": "admin", "passwd": "123", "id": "Manage"}

posted @ 2021-04-21 17:40  李成果  阅读(54)  评论(0编辑  收藏  举报