首页 > 编程语言 >python学习第六周总结

python学习第六周总结

时间:2022-11-14 20:57:15浏览次数:44  
标签:__ 总结 name python self 第六周 对象 print def

封装

封装:就是将数据和功能'封装'起来
隐藏:在类的定义阶段名字前面使用两个下划线表示隐藏。就是将数据和功能隐藏起来不让用户直接调用,而是开发一些接口间接调用,从而可以在接口内添加额外的操作
伪装:将类里面的方法伪装成数据,目的是调用方法可以像调用数据一样不用加括号

"""
隐藏类名称空间中名字的语法结构是在类的定义阶段名字前面加上__,那么通过类或者对象点名字的方式都无法直接找到这个名字,如果想要拿到语法结构为:类或对象._类名__名字
"""
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

相关文章

  • PYTHON_排序
    准备分模块积累,此模块为【递推】。编写程序,输入一个包含20个整数的列表,对其中偶数下标的元素进行降序排列,奇数下标的元素不变。输出排序后的列表。(提示:使用切片。)输入样......
  • 面向对象周总结
    面向对象之三大特性面向对象三大特性之封装封装:就是将数据和功能'封装'起来隐藏:将数据和功能隐藏起来不让用户直接调用而是开发一些接口间接调用从而可以在接口内......
  • python-装饰器
    装饰器:装饰器可以用来做什么?作用:可以在不修改功能函数内部代码的情况下,给功能函数进行扩展的新功能(对开放封闭原理)1.装饰器可以给当前的功能进行扩展......
  • 力扣278(java&python)-第一个错误的版本(简单)
    题目:你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本......
  • python 多进程 多线程 协程
    多进程-进程池1fromconcurrent.futuresimportProcessPoolExecutor23withProcessPoolExecutor(max_workers=10)asexecutor:4results=executor.map......
  • 从新开始学Python - 字符串扩展3
    字符串定义方法单引号双引号三个双引号,例如"""Python学习"""三个双引号与多行注释相同,也可以支持换行,如果不用变量接受,则为多行注释,如果用变量接受,则为字符串、......
  • 关于函数调用的总结
    首先强调的是:C语言中所有函数调用都是传值调用(数组是例外情况。C里数组名就表示了数组的首地址当把数组名当参数传递时,其实也就是传了个地址而已)1、传值调用......
  • 周总结7
    面向对象之封装,多态,反射派生实际应用importdatetimeimportjsonimportdatetimeimportjsonclassMyJsonEncoder(json.JSONEncoder):defdefault(s......
  • CodeStar第六周周赛普及进阶组
    T1:倍数序列3本题难度中等,思路和LIS类似,用dp[i]表示以\(a_i\)结尾的倍数序列的个数。如果\(a_i\)是\(a_j\)的倍数,倍数序列个数就是\(dp[j]\),枚举所有\(j\)求......
  • 51st 2022/11/12 模拟赛总结36
    这次按自己的话来说,不能接受因为和估分差距有点大赛时很开心地以为能A两题,一题50然后爆成120原因:T1的100->20现发现T1是因为没有全取模,很失落其实是因为考试时的一......