面向对象(4)
![image]()
1、组合
# 组合
'''
面向对象中组合的概念,其实本质上也是为了减少代码冗余,
核心思想是:对象的属性对应的不再是具体的一个值,而是一个对象,这样
我们在调用的时候就能很大程度的减少重复代码的编写
'''
'''
如果要给一个学生对象传入课程信息,
1、直接参数传入(太长,每次产生学生对象的话要传入的参数就太多了)代码冗余可读性不高
2、继承父类,定义一个course类,让学生类继承(学生只属于人类,) 偏离了继承的思想
3、定义完课程类之后,直接产生课程对象存入课程信息,把课程对象当做学生对象的属性保存——-》组合,减少了代码的冗余,可读性提高
'''
# 示例:以选课系统为例
class School:
# 初始化学校对象
def __init__(self, name):
self.name = name
self.Class = None
# 将学校与班级关联起来
def related_Class(self, Class_obj):
self.Class = Class_obj.name
def tell_Class(self):
print('%s %s' % (self.name, self.Class))
class Class:
def __init__(self, name):
self.name = name
self.course = None
# 班级与课程关联起来
def related_course(self, course_obj):
self.course = course_obj.name
def tell_course(self):
print('%s %s' % (self.name, self.course))
class Course:
def __init__(self, name):
self.name = name
self.student = None
# 将课程和学生关联起来
def related_student(self, student_obj):
self.student = student_obj.name
def tell_student(self):
print('%s %s' % (self.name, self.student))
class Student:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
self.course = []
def choose_course(self, course_obj):
self.course.append(course_obj)
def tell_course(self):
print('%s %s' % (self.name, self.course))
# 创建校区
school_obj1 = School('上海老男孩')
school_obj2 = School('北京老男孩')
# 开设班级
class_obj1 = Class('脱产14期')
class_obj2 = Class('脱产19期')
# 开设课程
course_obj1 = Course('python全栈开发')
course_obj2 = Course('linux运维')
# 实例化学生对象
student_obj = Student('jason', 'age', 'male')
# 将学校与班级关联起来
school_obj1.related_Class(class_obj1)
# 查看当前校区开设了哪些班级
school_obj1.tell_Class()
'''
面向对象的基本思想:可扩展性高,代码可读性好,从上面的例子可以很清楚的看出来,
当需要修改某一部分的内容时,只需要针对某一部分进行修改即可,对程序的整体功能影响不大。
'''
![image]()
2、内置方法(魔术方法)
- 1、什么是内置方法:
以双下__开头并以__双下结尾的内置方法
- 特点:在触发了某种条件时,自动执行方法
内置方法又叫魔术方法简称魔法
- 2、内置方法是用来干什么的:
内置方法的本质是为了定制化我们的类或者是对象,
让我们在使用时的结果能和我们预期的结果一样
# 1、__init__:只要在调用类实例化对象时就会自动执行该方法
class Foo:
def __init__(self):
print('哈哈哈')
obj = Foo() # 哈哈哈
# 2、__str__:
'''
在打印对象时自动触发,并且会打印出return后面的值,且返回的值只能是字符串类型
'''
# 示例:
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return '我执行了'
stu1 = Student('jason', 20)
print(stu1) # 我执行了
# 3、__del__
# 示例一:
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __del__(self):
print('我执行了')
stu1 = Student('jason', 20)
del stu1 # 我执行了
# 示例二:
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __del__(self):
print('我执行了')
stu1 = Student('jason', 20)
print('========>')
'''
========>
我执行了
'''
'''
从上面的两个例子可以看出来,__del__方法在程序结束前会自动执行,且在删除对象之前执行,
有一点可以确定的是,程序结束时pycharm会进行内存的释放,也就是python里的垃圾回收机制,
由此可以得出__del__方法的定义:
在执行清除数据之前执行的操作
有一点需要注意的是:我们在pycharm里的程序仅仅只是应用程序里的数据,当我们在后期的使用中,
对象里的某个属性涉及到对操作系统的内存空间进行操作时(打开关闭文件),
程序结束时是不会自动释放操作系统里占用资源的,这个时候就要利用__del__方法,
来达到对操作系统里的资源的释放
'''
# 3、__call__:在对象加括号时自动执行该方法
# 示例:
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __call__(self, *args, **kwargs):
print('我执行了')
stu1 = Student('jason', 20)
stu1() # 我执行了
'''
之前我们说了,python是一门面向对象的语言,即python里的一切皆对象,
下面以我们之前学的int为例
'''
a = int(10) # 这其实就是实例化对象的过程
print(a) # 10
'''
但是看似违背了我们对对象的认知,我们之前在直接打印对象时,返回的是对象的内存地址,
而不是一个确切的值,这个其实和我们上面说的__str__方法原理一样,python在内部已经为我们
封装好了,所以我们在调用时可以直接查看对应的值,所以可以说,python里一切皆对象
'''
# 再以列表为例
l = [1, 2, 3]
l.append(5) # 点的方式和我们在用对象调用类里的方法时是一样的,自动将对象传入方法
print(l) # [1, 2, 3, 5]
list.append(l, 6)
print(l) # [1, 2, 3, 5, 6]
'''
从上面的例子我们更加验证了’python里一切皆为对象‘这句话,类调用和对象在调用类里的方法时,
和我们自定义的对象和类调用时是一模一样的
'''
'''
基于以上原理,再来看一个例子,我们之前在打开文件时,都是用with...as...语法进行操作的,
但是他的内部原理又是什么,在这里先下个定义:
with...as...:
子代码块
上述语法结构又被称为'上下文管理协议'即with语句,
为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法'
'''
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __enter__(self):
print('enter执行了')
def __exit__(self, exc_type, exc_val, exc_tb):
print('exit执行了')
def read(self):
print('我也是')
with Student('jason', 18) as self:
print('执行我以后要就执行exit')
'''
enter执行了
执行我以后要就执行exit
exit执行了
'''
'''
从上面的情况我们可以发现一个很有趣的现象,enter在with语法出现时就自动执行了,
而exit是在with的子代码块执行结束以后才执行的,这和我们之前执行文件操作时是不是有什么相似之处?
事实上,我们当初在用with语法执行文件时,就是通过enter和exit语法实现对文件的操作时,并且我们
还知道一点,with语法在打开文件时会自动关闭文件,这是不是exit方法有点类似,也就是说我们只需要在exit方法
里加入关闭文件的操作就能理解当初为什么我们用with语法打开文件执行完以后会自动关闭文件了,其内部原理其实就是
利用enter和exit方法实现的
但是,需要补充的是,with语法不仅仅可以对文件操作,还可以对其他的类进行操作,这和我们上面提到的python里一切皆对象又形成了呼应,
所以我们常说的文件其实也是一个类,而我们所用的with open语法,其实就是调用了open类,而as后面的则是实例化的对象,并且通过
类调用的方式实例化一个对象,这也就是with语法(上下文管理协议)的内部原理
'''
![image]()
3、异常
# 异常
'''
1、什么是异常
异常就是代码运行产生的错误信息
2、异常三要素:
1、异常出现的位置:Tracback
2、异常类型:
1:语法异常
不被允许的,不能出现语法异常
eg:print(
ps:语法错误根本过不了python解释器检测语法阶段,因此是不被允许的,必须在程序执行前就进行修改
2:逻辑异常
可以被允许的,是不可避免的,
随着我们的代码量越来越多,逻辑异常也会随之增加,也就是我们常说的bug,
3、异常的详细信息:
记录了出现异常的详细原因
3、如何处理异常
4、为什么要使用异常处理:
增强代码的健壮性,减少出现的异常
'''
# 3、如何处理异常
'''
一般语法结构:
try:
可能出现异常的代码(被检测的代码尽量不能太多)
except 异常类型 as e: # e用来接收异常的详细信息
检测到异常时采取的相应措施
ps:except数量不限
万能语法结构:
try:
可能出现异常的代码(被检测的代码尽量不能太多)
except BaseException:
检测到异常时采取的相应措施
'''
# 异常处理包括的其他方法
'''
try:
可能出现异常的代码(被检测的代码尽量不能太多)
except 异常类型 as e: # e用来接收异常的详细信息
检测到异常时采取的相应措施
else:
不出现异常执行的代码块
finally:
不管报不报错都会执行的代码块
'''
# 主动抛出异常
a = int(input('>>>:'))
if a:
print(a)
else:
raise '出错啦'
# 断言
assert 1 == 1 # 条件为True正常执行
assert 1 == 2 # 条件为False触发异常AssertionError
![image]()