今日内容概要
- 组合
- 面向对象的内置函数(魔术方法、魔法)
- 反射
- 异常
内容详细
组合
# 什么是组合
就是一个对象拥有一个属性
但是该属性的值 是另外一个对象
# 继承
其实就可以描述为:
满足什么是什么的关系 is-a的关系
'''
is-a 从字面上看就表示"是一个"的意思 根据继承的特性
一个派生类对象(子类) 可以看成是一个基类(父类)对象
也就是说一个派生类对象"是一个"基类对象,所以这种名称符合对这种特性的概括。
'''
# 继承是一把双刃剑 并不是继承的越多越好 多继承尽量少一些
# 例1
class Foo:
def __init__(self, m):
self.m = m
class Bar():
def __init__(self, n):
self.n = n
obj = Foo(10) # m = 10
obj1 = Bar(20) # n = 20
obj.x = obj1 # obj.x就是一个组合 就是一个对象拥有一个属性obj.x 但是该属性的值 是另外一个对象obj1
print(obj.__dict__) # {'m': 10, 'x': <__main__.Bar object at 0x000001F73E14B470>}
# obj 就是一个超级对象 不仅可以拿自己对象中的属性 还可以拿到其他对象中的属性
print(obj.x.n) # 20 obj.x就相当于obj1
print(obj1.n) # 20
# 例2
# 父类
class People():
school = 'SH'
def __init__(self, name, age, gender, ):
self.name = name
self.age = age
self.gender = gender
class Admin(People):
pass
# 父类
class Course():
def __init__(self, name, period, price, ):
self.name = name
self.period = period
self.price = price
python = Course('python', '6mon', 10000) # 实例化对象 课程就出来了
linux = Course('linux', '5mon', 20000) # 实例化对象 课程就出来了
# 子类
class Student(People, Course):
def __init__(self, name, age, gender, course=None):
if course is None:
course = []
self.courses = course
super().__init__(name, age, gender, )
def choose_course(self, stu_obj, course):
stu_obj.courses.append(course)
stu = Student('ly', 19, 'male', 'python')
print(stu.name) # ly
stu = Student('ly', 20, 'male')
# 课程已经有过了
# python = Course('python', '6mon', 10000) # 实例化对象 课程就出来了
# linux = Course('linux', '5mon', 20000) # 实例化对象 课程就出来了
stu.courses.append(python)
stu.courses.append(linux)
print(stu.courses) # 内存地址 [<__main__.Course object at 0x00000186D04BB390>, <__main__.Course object at 0x00000186D04BB3C8>]
# 实例化后结果 [python, linux] 列表里面是两个内存地址
for course in stu.courses: # 通过内存地址空间中找属性
print(course.price)
# 10000
# 20000
# 子类
class Teacher(People, Course):
def __init__(self, name, age, gender, level):
self.level = level
super().__init__(name, age, gender, )
def score(self, stu_obj, score):
stu_obj.score = score
tea = Teacher('ly', 19, 'male', 10)
tea.course = linux
print(tea.course.name) # 课程名 linux
print(tea.course.price) # 课程价格 20000
print(tea.course.period) # 课程周期 5mon
面向对象的内置函数
# 1. __init__()
调用类的时候自动触发的方法
# 2. __str__()
只要打印对象的时候 就会自动触发的方法
# 3. __del__()
# 4. __enter__()
# 5. __exit__()
# 6. __call__()
# 1. __init__() 2. __str__()
class Student():
school = 'SH'
# 调用类的时候触发
def __init__(self, name, age):
self.name = name
self.age = age
def tell(self):
print('name: %s, age: %s' % (self.name, self.age))
# 只要打印对象的时候,就会自动触发的函数
# 但是返回值只能是字符串
def __str__(self):
return 'name:%s' % self.name
# return 123 报错 返回值只能是字符串
stu = Student('ly', 20)
print(stu) # name:ly 就相当于打印 print(stu.__str__())
f = open('a.txt', mode='w')
print(f) # 结果是经过底层处理的数据 <_io.TextIOWrapper name='a.txt' mode='w' encoding='cp936'>
# 3. __del__()
class Student():
school = 'SH'
# 调用类的时候触发
def __init__(self, name, age):
self.name = name
self.age = age
self.f = open('a.txt', 'r')
# 1. 手动执行del
# 2. 程序执行完毕触发
def __del__(self):
print('from __del__')
self.f.close()
stu = Student('ly', 19)
del stu.school # 报错 因为stu对象默认是空
del Student.school # from __del__ 后走
print('end=>>>>>>>>>>>>') # 先走
del stu.name # from __del__
print(stu.school)
print('end=>>>>>>>>>>>>')
# 4. __enter__() 5. __exit__()
class Open:
def __init__(self,name):
self.name=name
def __enter__(self):
print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量') # 1
return self
# return 123
# __enter__执行之后 继续执行with代码体
def __exit__(self, exc_type, exc_val, exc_tb): # with代码体 执行完之后 执行__exit__
print('with中代码块执行完毕时执行我啊') # 4
with Open('a.txt') as f:
print('=====>执行代码块') # 2
print(f) # <__main__.Open object at 0x00000246D7B793C8> # 3
print(f, f.name) # 5
# 6. __call__()
class Foo:
def __init__(self):
pass
# 对象加括号自动触发
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 执行 __init__
# 一切皆对象 对象就可以加括号
obj() # __call__
'''
a = list([1, 2, 3])
# a.append(4) # 就相当于 list.append(a, 4)
list.append(a, 5)
print(a) # [1, 2, 3, 5]
'''
反射
# 反射是指:对象通过字符串来操作属性
class Student():
school = 'sh'
def __init__(self, name, age):
self.name = name
self.age = age
def func(self):
print('from func')
stu = Student('ly', 18)
print(stu.name) # ly
print(stu."name") # 报错 不能直接用字符串
print(stu.__dict__['name']) # ly 存在则正常获取属性
print(stu.__dict__['name11']) # 不存在的情况直接报错
# 1. getattr
print(getattr(stu, 'name1', None)) # None 相当于 stu.name 第一个参数传对象 第二个传属性 第三个传找不到的返回结果
stu.func() # from func 直接调用
print(getattr(stu, 'func')) # 通过字符串调用 <bound method Student.func of <__main__.Student object at 0x0000020BB6FBBD30>>
getattr(stu, 'func')() # from func 必须掌握
# 2. setattr
setattr(stu, 'x', 123) # 第一个传对象 第二个传属性名 第三个传属性值
print(stu.__dict__) # {'name': 'ly', 'age': 18, 'x': 123}
# 3. hasattr
print(hasattr(stu, 'name')) # True 确认对象中是否有属性 第一个传对象 第二个传属性
print(hasattr(stu, 'name1')) # False
# 4. delattr
delattr(stu, 'name') # 删除 第一个传对象 第二个传属性
print(stu.__dict__) # {'age': 18}
# 类也可以使用
print(getattr(Student, 'school'))
# 模块也可以使用
import time
time.sleep(1)
getattr(time, 'sleep')(2)
# 导模块底层写法 __import__('time') 就相当于 import time
time = __import__('time') # 就相当于 import time 导入模块
time.sleep(3) # 用法一样
异常
1.什么是异常
异常就是错误发生的信号
'''如果不对该信号做处理 那么异常之后的代码不会执行'''
# 异常种类
语法错误
不被允许的 print(12
逻辑错误
被允许 但尽量不要出现
a = [1, 2, 3]
print(a[5])
2.为什么要用异常
增强代码的健壮性
3.怎么用异常
try:
被监测代码
except 异常的类型:
pass # 异常处理流程
except 异常的类型:
pass # 异常处理流程
except 异常的类型:
pass # 异常处理流程
except Exception as e: # 万能异常 不管什么类型错误 都可以接收
pass
else:
# 当被监测代码没有发生异常的时候,触发的
pass
finally:
不管被监测的代码有没有出错,都执行
pass