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"}
Python语言系列-07-面向对象2的更多相关文章
- Python语言系列-05-模块和包
自定义模块 #!/usr/bin/env python3 # author:Alnk(李成果) # 为什么要有模块?(内置函数不够用) # 和操作系统打交道 # 和python解释器打交道 # 和时间 ...
- Python学习系列之面向对象
概述 一.Python编程方式 面向过程编程:根据业务逻辑从上到下磊代码 面向函数编程:将某功能代码封装到函数中,将来直接调用即可,无需重新写 面向对象编程:对函数进行分类.封装 二.面向过程编程 w ...
- Python语言系列-06-面向对象1
楔子 #!/usr/bin/env python3 # author:Alnk(李成果) # 人狗大战例子引入面向对象 # 版本1 def hero(name, sex, hp, ce, level= ...
- Python语言系列-02-基础数据类型
格式化输出 #!/usr/bin/env python3 # author:Alnk(李成果) # 百分号% 格式化输出 name = input('姓名:') age = input('年龄:') ...
- Python语言系列-10-数据库
MySQL 基础环境准备 readme.txt 作者:Alnk(李成果) 版本:v1.0 安装mysql数据库 略 创建student库 # mysql> create database stu ...
- Python语言系列-09-socket编程
简介 软件开发的架构 1.C/S架构(client-server) 2.B/S架构 (browser-server) 网络基础概念 网络三要素: 1.ip 2.port 3.通信协议:TCP.UDP ...
- Python语言系列-08-面向对象3
反射 #!/usr/bin/env python3 # author: Alnk(李成果) # 反射 # hasattr getattr setattr delattr class Animal(ob ...
- Python语言系列-01-入门
python的出生与应用 #!/usr/bin/env python3 # author:Alnk(李成果) """ 1,python的出生与应用 python的创始人为 ...
- Python语言系列-04-高阶函数
闭包 #!/usr/bin/env python3 # author:Alnk(李成果) # 什么是闭包 # 1,闭包存在于函数中 # 2,闭包就是内层函数对外层函数(非全局变量)的引用 # 3,最内 ...
随机推荐
- 海量数据Excel报表利器——EasyExcel(一 利用反射机制导出Excel)
EasyExcel 写入(导出) 互联网的精髓就是共享,可以共享技术.共享经验.共享情感.共享快乐~ 很多年前就有这个想法了,从事IT行业时间也不短了,应该把自己工作和业余所学习的东西记录并分享出来, ...
- js--你需要知道的字符串使用方法(含es6及之后)
前言 字符串作为 JavScript 的基本数据类型,在开发以及面试过程中作为程序员对基础掌握情况的重要考点,本文来总结一下字符串的相关属性以及用法.包含了ES6中的一些新语法特性. 正文 1.字符串 ...
- pip 下载时出现问题TypeError: unsupported operand type(s) for -=: 'Retry' and 'int'
我这里解决就是更新下载源,马德,中科的源居然不够快,我就只能换源了,一换就成功了 1.一次性(临时使用): 可以在使用pip的时候加参数-i https://pypi.tuna.tsinghua.ed ...
- springboot项目启动,停止,重启
参考博客 https://www.cnblogs.com/c-h-y/p/10460061.html 打包插件,可以指定启动类 <build> <plugins> <pl ...
- 羊城杯wp babyre
肝了好久,没爆破出来,就很难受,就差这题没写了,其他三题感觉挺简单的,这题其实也不是很难,我感觉是在考算法. 在输入之前有个smc的函数,先动调,attach上去,ida打开那个关键函数. 代码逻辑还 ...
- 你会用哪些JavaScript循环遍历
总结JavaScript中的循环遍历定义一个数组和对象 const arr = ['a', 'b', 'c', 'd', 'e', 'f']; const obj = { a: 1, b: 2, c: ...
- vue3后台管理系统(模板)
系统简介 此管理系统是基于Vite2和Vue3.0构建生成的后台管理系统.目的在于学习vite和vue3等新技术,以便于后续用于实际开发工作中: 本文章将从管理系统页面布局.vue路由鉴权.vuex状 ...
- Python使用笔记005-文件操作(二)
1.1 打开文件模式 # r r+ r+读是没问题的,写的话,会覆盖原来的内容,文件不存在时会报错# w w+ w+用来新的文件没问题,旧的文件会覆盖原来的内容# a a+ a+写是追加,读不到是因为 ...
- gpasswd简单记录
gpasswd [option] GROUP 一切都是为了权限 gpasswd常用参数: -a, --add USER 将user用户加入到组中 -d, --delete USER 将user用户 ...
- C语言:GB2312编码和GBK编码,将中文存储到计算机
计算机是一种改变世界的发明,很快就从美国传到了全球各地,得到了所有国家的认可,成为了一种不可替代的工具.计算机在广泛流行的过程中遇到的一个棘手问题就是字符编码,计算机是美国人发明的,它使用的是 ASC ...