封装
封装:就是将数据和功能'封装'起来
隐藏:在类的定义阶段名字前面使用两个下划线表示隐藏。就是将数据和功能隐藏起来不让用户直接调用,而是开发一些接口间接调用,从而可以在接口内添加额外的操作
伪装:将类里面的方法伪装成数据,目的是调用方法可以像调用数据一样不用加括号
"""
隐藏类名称空间中名字的语法结构是在类的定义阶段名字前面加上__,那么通过类或者对象点名字的方式都无法直接找到这个名字,如果想要拿到语法结构为:类或对象._类名__名字
"""
class Myclass:
school_name = '清华大学'
_ = '嘿嘿嘿'
_name = 'max'
"""
类在定义阶段,名字前面有两个下划线,那么名字会被隐藏起来,无法直接访问
"""
__age = 25
"""
在python中,没有真正的隐藏,仅仅是换了个名字
"""
def __choice_course(self):
print('选课系统')
print(Myclass.school_name) # 清华大学
obj = Myclass()
print(obj.school_name) # 清华大学
print(Myclass._) # 嘿嘿嘿
print(obj._) # 嘿嘿嘿
print(Myclass._name) # max
print(obj._name) # max
print(Myclass.__age) # 会报错,因为__被隐藏
print(Myclass._Myclass__age) # 25
print(obj._Myclass__age) # 25
Myclass.__gender = 'male'
print(Myclass.__gender) # male 手动添加的类的名字无法隐藏
obj = Myclass()
obj.__addr = 'shanghai'
print(obj.__addr) # shanghai 手动添加对象的名字无法隐藏
"""
除了类,对象也可以设置隐藏属性,但是只能在类体中设置,对象在类体中设置独有方式的方法就只有__init__方法。类体代码中可以直接用隐藏的名字
"""
class Person:
def __init__(self, name, age, hobby):
self.__name = name #对象也可以拥有隐藏的属性
self.__age = age
self.__hobby = hobby
def get_info(self):
'''类体代码中可以直接用隐藏的名字'''
print(f"""
姓名:{self.__name}
年龄:{self.__age}
爱好:{self.__hobby}
""")
'''隐藏的属性开放修改的接口,可以自定义很多功能,在这里定义一个修改功能'''
def set_name(self, new_name):
if len(new_name) == 0:
raise ValueError('修改的姓名不能为空')
if new_name.isdigit():
raise ValueError('名字不能是数字')
self.__name = new_name
obj = Person('max', 25, 'fitness')
obj.get_info()
"""
如果用__dict__查看对象名称空间,发现字典中所有的键都变成了:_类名__名字,所以说我们也可以通过对象名.__类名_名字的方式来拿对象的名字,但是不建议
"""
伪装
"""
类中有的功能返回值是一个数字,而我们调用的时候仍需要像调用函数一样调用,此时可以通过@property来装饰功能,使被装饰的功能从调用方式上来说更像一个数据
"""
BMI指数:衡量一个人的体重与身高对健康影响的一个指标
BMI=体重(kg)÷身高^2(m)
class Person(object):
def __init__(self, name, height, weight):
self.name = name
self.height = height
self.weight = weight
def BMI(self):
return self.weight / (self.height ** 2)
p1 = Person('max', 1.82, 70)
print(p1.BMI()) # 21.132713440405748
有了@property之后功能BMI更像是一个数据,但是用该方法伪装不能加参数
class Person(object):
def __init__(self, name, height, weight):
self.name = name
self.height = height
self.weight = weight
@property
def BMI(self):
return self.weight / (self.height ** 2)
p1 = Person('max', 1.82, 70)
print(p1.BMI) # 21.132713440405748
"""
当用property修饰之后的函数无法用对象名点名字的方式修改,此时用@函数名.setter修饰一个修改的函数,用户可以直接用对象名点的方式来修改
"""
class Foo:
def __init__(self, val):
self.__NAME = val
@property
def name(self):
return self.__NAME
@name.setter
def name(self, value):
if not isinstance(value, str):
raise TypeError('%s必须是字符串' % value)
self.__NAME = value
@name.deleter
def name(self):
raise PermissionError('Can not delete')
f1 = Foo('jason')
print(f1.name) # jason
f1.name = 'max' # 触发name.setter装饰器对应的函数
print(f1.name) # max
del f1.name # PermissionError: 不能被删除
# 触发name.deleter对应的函数name(f),抛出异常PermissionError
"""
用property装饰后的功能类似一个数据,查的时候只需要对象名点功能名即可查到。同样改和删也是以对象点函数名的方式来执行,改是用对象名点函数名等于新的值来调用修改功能,和之前的调用方式不同
"""
多态
1.多态:多态是指一种食物可以有多种形态但是针对相同的功能应该设定相同的方法,这样无论我们拿到的是哪个具体事务,都可以通过相同的方法调用功能(多态类型下父类的功能不再是为了省代码,而是提示每一个子类如果想要达成相同的目的必须要有相同的方法)
class Animal:
def spark(self):
pass
def Cat(Animal):
def spark(self)
print('喵喵喵')
def Dogs(Animal):
def spark(self)
print('汪汪汪')
def Pig(Animal):
def spark(self)
print('哼哼哼')
"""
面向对象中多态意思是,一种事物可以有多种形态但是针对相同的功能应该定义相同的方法,这样无论我们拿到的是哪个具体的事物,都可以通过相同的方法调用功能
"""
s1 = 'hello world'
l1 = [11, 22, 33, 44]
d = {'name': 'jason', 'pwd': 123}
print(s1.__len__())
print(l1.__len__())
print(d.__len__())
2.鸭子类型:只要你看上去像鸭子,走路像鸭子,说话像鸭子,那么你就是鸭子。以linux系统为例,文件能够读取数据也可以保存数据,内存能够读取数据也能保存数据吧,硬盘能够读取数据也能保存数据,所以在linux中有句话叫一切皆文件
eg:
class File:
def read(self): pass
def write(self): pass
class Memory:
def read(self): pass
def write(self): pass
class Disk:
def read(self): pass
def write(self): pass
反射
反射:利用字符串操作对象和数据的方法,可以动态地向对象中添加属性和方法
1.hasattr():
判断对象是否含有某个字符串对应的属性名或方法名
用法:hasaattr(obj,str),判断输入的str字符串在对象obj中是否存在(属性或方法),存在返回True,否则返回False
2.getattr():
根据字符串获取对象对应的属性名(数据)或方法(函数体代码)
用法:getattr(obj,str),将按照输入的str字符串在对象obj中查找。如找到同名属性,则返回该属性;如找到同名方法,则返回方法的引用,想要调用此方法得使用 getattr(obj,str)()进行调用.如果未能找到同名的属性或者方法,则抛出异常:AttributeError。
3.setattr():
根据字符串给对象设置或者修改数据
用法:setattr(obj,name,value),name为属性名或者方法名,value为属性值或者方法的引用
(1) 动态添加属性。如上
(2)动态添加方法。首先定义一个方法。再使用setattr(对象名,想要定义的方法名,所定义方法的方法名)
4.delattr():
根据字符串删除对象里面的名字
用法:delattr(obj,str),将你输入的字符串str在对象obj中查找,如找到同名属性或者方法就进行删除
"""
判断某个名字对象是否存在
"""
class School:
school_name = '小姐姐学院'
def choice_course(self):
print('选课系统')
obj = School
try:
obj.school_name
except Exception:
print('没有这个名字')
else: # try的子代码为True时走else子代码
print('名字存在哦')
# 执行结果:名字存在哦
"""
请结合用户输入,查看用户输入的名字是否存在
"""
class School:
school_name = '小姐姐学院'
def choice_course(self):
print('选课系统')
obj = School
target_name = input('请输入您想查看的名字>>>:').strip()
try:
obj.target_name
except Exception:
print('没有这个名字')
else:
print('名字存在哦')
# 执行结果:没有这个名字
"""
因为获取用户输入得到的是字符串,而对象点的是变量名。反射的作用就是利用字符串操作对象的数据和方法
"""
print(hasattr(obj, 'school_name')) # True
print(getattr(obj, 'school_name')) # 小姐姐学院
print(getattr(obj, 'choice_course')) # <function School.choice_course at 0x0000020D15538598>
"""
hasattr和getattr找对象的数据和方法首先从对象名称空间中找,其次从产生对象的类名称空间中找,找不到再去父类名称空间中找
"""
class A:
name = 'jason'
class B(A):
pass
b = B()
print(getattr(b, 'name')) # jason
"""
判断用户输入的名字是否存在,如果存在则执行
"""
class C1:
school_name = '小姐姐学院'
def choice_course(self):
print('选课系统')
obj = C1()
while True:
target_name = input('请输入您想要操作的名字>>>:').strip()
if hasattr(obj, target_name):
print('恭喜你,系统中有名字')
data_or_func = getattr(obj, target_name)
if callable(data_or_func):
print('您本次执行的是系统中的方法')
data_or_func()
else:
print('您本次执行的是系统中某个数据')
print(data_or_func)
else:
print('系统当中未找到该名字')
面向对象的魔法方法
魔法方法:类中定义的双下方法都称为魔法方法
使用方法:不需要认为调用,在特定条件下自动触发运行
eg:__init__是创建对象之后自动触发给对象添加独有数据的方法
1.__init__:添加对象独有数据的方法,对象添加数据时自动触发
class A:
def __init__(self, name):
self.name = name
print('__init__')
#类名加括号,给对象添加独有数据的方法
obj = A('max') # obj = A('max')
2.__str__:对象在被执行打印操作的时候自动触发,用法是在类体代码中定义__str__(self),先生成一个对象,在print(对象名),就可以自动触发打印返回值
class A:
def __str__(self):
'''对象在被执行打印操作的时候自动触发,并且返回什么执行结果就是什么'''
return '哈哈哈' # __str__子代码中不能用print,只能用return返回
a = A()
print(a) # 哈哈哈
"""
返回值只能是字符串,非字符串数据类型会报错
"""
class A:
def __str__(self):
return 123
a = A()
print(a) # 报错
"""
maximum recursion depth:最大递归深度;此代码报错原因是print(a)会自动触发__str__并且返回f'{self}说:哈哈哈',此时print(a就相当于print(f'{self}说:哈哈哈'),print里面反复递归对象a,直到达到最大递归深度报错,所以返回的字符串中不能有对象本身
"""
class A:
def __str__(self):
return f'{self}说:哈哈哈'
a = A()
print(a) # 错误信息:RecursionError: maximum recursion depth exceeded while calling a Python object
"""
这个特性也可以用来分辨对象具体是谁, 返回的字符串中不能有对象本身,但可以点名字来看具体是哪个对象
"""
class A:
def __init__(self, name):
self.name = name
def __str__(self):
return f'对象{self.name}'
a = A('max')
print(a) # 对象max
3.__call__:对象加括号调用,该方法返回什么对象调用的返回值就是什么
class A:
def __init__(self, name):
self.name = name
def __str__(self):
return f'对象{self.name}'
def __call__(self, *args, **kwargs):
print('__call__')
return '__call__的返回值'
a = A('max')
print(a()) # __call__ # __call__的返回值
"""
对象类似于函数名,可以在括号内加上位置参数和关键字参数,打印args和kwargs可以看到他们分别收集了括号内的位置参数和关键字参数,对象名加括号可以调用__call__,print(res)还可以接受到__call__的返回值
"""
class A:
def __init__(self, name):
self.name = name
def __str__(self):
return f'对象{self.name}'
def __call__(self, *args, **kwargs):
print(args, kwargs)
return '__call__的返回值'
a = A('max')
res = a(123, '123', name='max') # (123, '123') {'name': 'max'}
print(res) #__call__的返回值
4.__getattr__:对象点的名字不存在时自动触发
class A:
def __init__(self, name):
self.name = name
def __getattr__(self, item):
return '很抱歉你找的名字不存在'
a = A('max')
print(a.name) # max
print(a.age) # 很抱歉你找的名字不存在
5.__getattribute__:对象在查找名字时会自动触发,不管名字是否存在,并且只要有__getattribute__在,__getattr__会自动失效,例题中a.age不存在但是但是依然返回了'嘿嘿嘿',是因为__getattribute__作用将__getattr__覆盖
class A:
def __init__(self, name):
self.name = name
def __getattr__(self, item):
return '很抱歉你找的名字不存在'
def __getattribute__(self, item):
return '嘿嘿嘿'
a = A('max')
print(a.name) # 嘿嘿嘿
print(a.age) # 嘿嘿嘿
"""
打印__getattribute__括号内的item后发现是一个对象名点的名字
"""
class A:
def __init__(self, name):
self.name = name
def __getattr__(self, item):
return '很抱歉你找的名字不存在'
def __getattribute__(self, item):
print(item)
return '嘿嘿嘿'
a = A('max')
print(a.age) # age 嘿嘿嘿
5.__setattr__:当对象执行对象名.名字=值的时候(对象定义独有的数据或修改数据)就会自动触发
class A:
def __init__(self, name):
'''第一步:self此时就是a,满足对象名.名字=值,所以会执行一次__setattr__'''
self.name = name
def __setattr__(self, key, value):
print('__setattr__')
a = A('max')
a.name = 'jack' # __setattr__ __setattr__
'''第二步,再执行一次__setattr__'''
"""
__setattr__(self, key, value)中的key和value分别指name和值max
"""
class A:
def __init__(self, name):
self.name = name
def __setattr__(self, key, value):
print('__setattr__')
print(key, value)
class Student:
def __init__(self, name):
self.name = name
a = A('max') # __setattr__ # name max
用__setattr__修改属性名:
obj1 = Student('max')
print(obj1.__dict__) # {'name': 'max'}
obj1.__setattr__('name', 'jason')
print(obj1.__dict__) # {'name': 'jason'}
6.__enter__:当对象跟在with后面,被当做上下文管理操作开始会自动触发__enter__。
__exit__:当对象参与with上下文管理语法运行完毕后自动触发(with子代码运行完毕)
class A:
def __init__(self, name):
self.name = name
def __enter__(self):
print('enter')
return 123
def __exit__(self, exc_type, exc_val, exc_tb):
print('exit')
return 234
a = A('max')
with a as f:
print(f) # enter 123 exit
"""
a = A('max')
with a as f:
pass # enter exit
"""
由此得出,f拿到的是__enter__的返回值
魔法方法笔试题
1.补全下列代码使得运行不报错即可:
class Context:
pass
with Context() as f:
f.do_something()
"""
分析:有with 对象,说明with参与上下文管理,必须要有__enter__方法,结束时必须要有__exit__(这两者一般会联合使用)。此外do_something()还没有定义,还需要定义一个功能do_something(),调用时才不会报错
"""
class Context:
def do_something(self):
pass
def __enter__(self):
return self
'''此行代码执行完毕需要一个f来点do_dometging(),我们一般用的最多的就是对象点的方式,所以此处需要返回对象本身也就是self。正好上节说道f拿到的是__enter__的返回值,所以旭阳将对象本身返回给f,再用对象点名字。所以return后面要跟self'''
def __exit__(self, exc_type, exc_val, exc_tb):
pass
with Context() as f:
f.do_something()
2.请定义一个字典,该字典可以通过点的方式来取值
"""
我们之前学过点的方式取值,但是之前是通过对象点名字来取名称空间中的名字,而本题要求字典点的方式来取字典中的值,两者有本质区别
"""
'''1.定义一个类,该类可以派生字典里所有的方法'''
class Mydict(dict):
'''2.由于添加键值对要通过点的方式来进行,那么可以联想到魔法方法中的__setattr__方法,该方法在对象名点名字=值时调用,且此时的key就指name,value指'max' '''
def __setattr__(self, key, value):
'''3.此时self就是obj,也就是构建的临时字典,通过按K取值的方式定义好取值方式'''
self[key] = value
'''4.定义好了添加键值对,此时再考虑取值。__getattr__特点是遇到名称空间中找不到的名字会自动触发,由于对象、类名称空间中都为空,所以查找名字肯定会自动触发__getattr__,且item是对象后面点的名字'''
def __getattr__(self, item):
'''5.返回一个通过item取到的值'''
return obj.get(item)
obj = Mydict()
obj.name = 'max'
print(obj.name)
元类简介
元类概念推导:
步骤1:如何查看数据的数据类型
s1 = 'hello world' # str()
l1 = [11, 22, 33, 44] # list()
d1 = {'name': 'jason', 'pwd': 123} # dict()
t1 = (11, 22, 33, 44) # tuple()
print(type(s1)) # <class 'str'>
print(type(l1)) # <class 'list'>
print(type(d1)) # <class 'dict'>
print(type(t1)) # <class 'tuple'>
步骤2:type不仅可以查看数据类型,也可以查看产生对象的类名
class Group:
pass
obj = Group()
print(type(obj)) # <class '__main__.Group'>
步骤3:type(对象名)结果是类名,那么type(类名)的结果是什么呢?
class Group:
pass
obj = Group()
print(type(obj)) # <class '__main__.Group'>
print(type(Group)) # <class 'type'>
type的父类依然是type
print(type(type)) # <class 'type'>
"""
结论:我们定义的类归根结底都是type产生的,所以我们把产生类的类(type)叫做元类
"""
创建类的两种方式
方式1:通过关键字class创建
class Teacher:
name = 'jason'
age = 18
a = Teacher()
print(a.name, a.age) # jason 18
方式2:通过关键字type创建,语法结构:type(类名, 类的父类, 类的名称空间)
Teacher = type('Teacher', (), {'name': 'jason', 'age': 18})
a = Teacher()
print(a.name, a.age) # jason 18
"""
也可以继承父类中的名字(如果只有一个父类后面需加逗号,同元组)
"""
class Person:
def work(self):
print('人不能不上班')
Teacher = type('Teacher', (Person,), {'name': 'jason', 'age': 18})
a = Teacher()
print(a.work()) # 人不能不上班 None
元类参与类的产生行为
"""
在某一步设定一些条件,来干涉类产生的行为,对象是由类加括号产生的,类是由元类加括号产生的。
对象是由类名加括号产生的 __init__
类是由元类加括号产生的 __init__
"""
class MyMetaClass(type):
def __init__(cls, what, bases=None, dict=None):
print('what', what) # what Student
print('bases', bases) # bases ()
print('dict', dict) # dict {'__module__': '__main__', '__qualname__': 'Student', 'name': 'max'}
super().__init__(what, bases, dict)
'''通过metaclass=MyMetaClass来继承元类'''
class Student(metaclass=MyMetaClass):
name = 'max'
"""
通过依次打印what, bases, dict得知,what是继承了MyMetaClass的类,dict是类Student的名称空间
"""
class MyMetaClass(type):
def __init__(cls, what, bases=None, dict=None):
# print('what', what) # what Student
# print('bases', bases) # bases ()
# print('dict', dict) # dict {'__module__': '__main__', '__qualname__': 'Student', 'name': 'max'}
if not what.istitle():
raise TypeError('首字母必须大写')
super().__init__(what, bases, dict)
class student(metaclass=MyMetaClass):
name = 'max' # TypeError: 首字母必须大写
class Student(metaclass=MyMetaClass):
name = 'max' # 可以正常创建
元类参与对象的产生行为
"""
对象加括号会执行产生该对象类里面的__call__
推导得出:类加括号会执行产生该类的类里面的__call__
"""
"""
给对象添加一些独有数据,首先是传到了元类里面的__call__,位置参数传给了args,关键字参数传给了kwargs,其次再交给__init__
"""
class MyMetaClass(type):
def __call__(self, *args, **kwargs):
print('__call__')
print(args, kwargs)
super().__call__(*args, **kwargs)
class Student(metaclass=MyMetaClass):
def __init__(self, name, age, gender):
print('__init__')
self.name = name
self.age = age
self.gender = gender
obj = Student('max', 25, 'male')
'''
执行结果:
__call__
('max', 25, 'male') {}
__init__
'''
要求:定义一个类,声称对象只能上传关键字参数
class MyMetaClass(type):
def __call__(self, *args, **kwargs):
if args:
raise TypeError('必须要传关键词参数哦')
'''super语句前面一定要加上return,不加会报错'''
return super().__call__(*args, **kwargs)
class Student(metaclass=MyMetaClass):
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
# obj = Student('max', 25, 'male') # TypeError: 必须要传关键词参数哦
obj = Student(name='max', age=25, gender='male')
print(obj.__dict__) # {'name': 'max', 'age': 25, 'gender': 'male'}
"""
分析:为什么要用类Student继承元类MyMetaClass呢?
因为对象产生的过程中首先把参数传入MyMetaClass的__call__,只有用Student继承元类MyMetaClass才能介入对象的生成过程。
如果args布尔值为True说明上传了关键字参数,这种情况下主动报错,报错情况下不会执行,只有args布尔值为Flase时才会执行super语句
"""
设计模式简介
1.设计模式:前人通过大量的验证创建出来解决一些问题的固定高效方法
2.IT行业目前有23种设计模式。分类:创建型、结构型、行为型
3.单例模式
类加括号无论执行多少次永远只会产生一个对象
目的:
当类中有很多非常强大的方法 我们在程序中很多地方都需要使用
如果不做单例 会产生很多无用的对象浪费存储空间
我们想着使用单例模式 整个程序就用一个对象
单例模式实现
方式1:类中存储单例
class C1:
__isinstance = None # 1.定义一个全局变量
def __init__(self, name, age):
self.name = name
self.age = age
'''通过这种方法产生一个固定的对象,并且只能调用此种方式产生'''
@classmethod
def singleton(cls): # 2.通过classmethond修饰的函数可以直接将类传进去
if not cls.__isinstance: # 3.判断,通过类.名字的方式拿到类中的数据
cls.__isinstance = cls('max', 123) # 4.如果cls.instance为None,则把它修改为一个对象,cls('max', 123)是一个对象
return cls.__isinstance # 5.返回刚刚生成的对象,拿到的返回值都是对象C1('max', 123)
obj1 = C1.singleton()
obj2 = C1.singleton()
print(id(obj1), id(obj2))
# 1952330470792 1952330470792
"""
此种方法也可以产生正常的对象,不调用singleton方法就可以正常产生
"""
方法2:通过模块来实现单例模式
md.py文件中代码:
class C1:
def __init__(self, name):
self.name = name
obj = C1('jason')
另一个py文件:
import md
print(id(md.obj)) # 2278381247176
print(id(md.obj)) # 2278381247176
方式3:元类控制单例类的产生
class MyType(type):
def __init__(cls, what, bases=None, dict=None): # 1.定义一个类
cls.__instance = cls.__new__(cls) # 2.用双下__new__产生一个新对象
cls.__init__(cls.__instance, 'jason', 18) # 3.添加对象独有的数据
super().__init__(what, bases, dict) # 4.继承元类其它的方法
def __call__(cls, *args, **kwargs): # 6.类的对象加括号调用类的__call__,子类加括号调用父类__call__
if args or kwargs: # 7.如果子类中传了值,就正常给对象添加独有数据,并且返回该对象
obj = cls.__new__(cls)
cls.__init__(obj, *args, **kwargs)
return obj
return cls.__instance # 8.如果子类对象没有添加数据,则返回之前创建的对象
class Mysql(metaclass=MyType): # 5.定义类Mysql,父类是MyType
def __init__(self, name, age):
self.name = name
self.age = age
obj1 = Mysql() # 9.所以Mysql产生的对象如果不加参数
obj2 = Mysql()
print(id(obj1), id(obj2)) # 2675820190128 2675820190128
pickle序列化
1.优势:能够序列化python中所有的类型
2.缺陷:只能够在python中使用,无法跨语言传输
3.功能:产生一个对象并且保存在文件中,取出时还是一个对象
class C1:
def __init__(self, name, age):
self.name = name
self.age = age
def func1(self):
print('from func1')
def func2(self):
print('from func2')
obj = C1('max', 25)
import json
with open(r'a.txt', 'w', encoding='utf8') as f:
json.dump(obj, f) # TypeError: Object of type C1 is not JSON serializable,说明json模块无法将对象存入文件
import pickle
with open(r'a.txt', 'wb') as f:
pickle.dump(obj, f)
with open(r'a.txt', 'rb')as f:
data = pickle.load(f)
print(data) # <__main__.C1 object at 0x000001F214678C50>
data.func1() # from func1
data.func2() # from func2
print(data.name) # max
选课系统思路
1.管理员功能
注册功能
"""
1.获取用户输入的用户名和密码,传到第二层
2.根据类名和用户名获取到用户对象,如果有对象说明用户已注册,返回False
3.如果对象不存在则创建新的对象并保存,返回True
"""
登录功能
"""
1.获取用户输入的用户名和密码,传到第二层
2.根据类名和用户名获取到用户对象,如果有没有对象说明用户未注册,返回False
3.如果能找得到对象,并且密码可以和对象中的密码(对象独有的数据)对上,那么返回True,并且修改记录用户登陆的字典
"""
创建学校
"""
1.事先在models中创建好School的类,包含名字和地址属性
2.在第一层获取学校的名字和地址,传入第二层
3.先利用学校名获取学校对象,如果学校已经存在则返回已注册,不存在则利用管理员对象点方法的形式生成学校对象
"""
创建课程
"""
1.先循环打印所有的学校,让用户选择添加课程的学校
2.获取用户输入得到课程信息,将课程信息,目标学校,管理员姓名传入第二层
3.查看该课程是否在学校的课程列表中,如果存在则返回信息无法添加,如果不在则利用管理员对象创建课程对象
4.在学校对象的课程列表中添加该课程
"""
创建老师
"""
1.获取用户输入,得到老师姓名和密码
2.传给第二层,生成老师对象,如果对象存在说明已经注册过,无法创建;如果对象不存在可以正常创建
"""
2.讲师功能
登录功能
"""
1.获取用户输入的用户名和密码,传到第二层
2.根据类名和用户名获取到用户对象,如果有没有对象说明用户未注册,返回False
3.如果能找得到对象,并且密码可以和对象中的密码(对象独有的数据)对上,那么返回True,并且修改记录用户登陆的字典
"""
查看课程
"""
1.循环遍历所有学校,供用户选择
2.用学校名拿到学校对象,返回课程列表
"""
选择课程
"""
1.循环打印所有的课程,供老师选择,建立一个临时列表,选择的课程添加在临时列表里
2.用集合去重的特性将老师原来的课程列表和临时课程列表合二为一,修改老师的课程列表
3.课程列表中逐一添加老师
"""
查看学生分数
"""
1.先在第二层获取该老师教授的课程列表,返回第一层
2.循环打印课程列表,让用户选择一门课程
3.在第二层获取该门课程的学生列表,并且利用字典生成式返回该学生的成绩字典
"""
修改学生分数
"""
1.先获取老师教授的课程列表,循环打印让老师选择目标课程
2.在第二层获取该课程的学生列表,并返回第一层让用户选择目标学生
3.获取用户输入的目标课程的最新分数,将目标课程,最新分数,学生姓名,老师姓名传入第二层
4.获取学生对象,再拿到学生的成绩字典,修改,保存
"""
3.学生功能
注册功能
"""
1.获取用户输入的用户名和密码,传到第二层
2.根据类名和用户名获取到用户对象,如果有对象说明用户已注册,返回False
3.如果对象不存在则创建新的对象并保存,返回True
"""
登录功能
"""
1.获取用户输入的用户名和密码,传到第二层
2.根据类名和用户名获取到用户对象,如果有没有对象说明用户未注册,返回False
3.如果能找得到对象,并且密码可以和对象中的密码(对象独有的数据)对上,那么返回True,并且修改记录用户登陆的字典
"""
选择学校
"""
1.循环打印所有学校名字
2.让用户选择学校;在第二层获取学生对象,用点的方式查看用户是否已选学校
3.如果有则无法修改学校,没有则在对象中添加学校
"""
选择课程
"""
1.先获取学生对象,然后判断学生是否已选学校,如果已选学校,返回学校课程列表
2.在第一层循环遍打印课程列表,让用户选择要添加的课程,形成一个临时字典
3.用集合将临时字典和旧的学生课程列表合二为一,修改学生的课程列表
4.遍历新的学生课程列表,更新成绩字典
"""
查看成绩
"""
1.全局名称空间中的学生姓名传到第二层,生成学生对象
2.直接返回成绩字典
"""
标签:__,总结,name,python,self,第六周,对象,print,def
From: https://www.cnblogs.com/zkz0206/p/16890350.html