day25 组合和内置函数
一、组合
# 解决类与类之间代码冗余问题:
1. 继承
2. 组合
组合:一个对象拥有一个属性, 属性的值必须是另外一个对象
继承满足的是:什么是什么的关系 # is-a
组合满足的是:什么有什么的关系 # has-a
案例1:
class People:
school = 'SH'
def __init__(self,name,age,gender,sourse=None):
if sourse is None:
self.course = []
self.name = name
self.age = age
self.genter = gender
class Course():
def __init__(self,course_name,course_period,course_price):
self.course_name = course_name
self.course_period = course_period
self.course_price = course_price
python = Course('python','5mio',1000)
linux = Course('linux','6mio',2000)
# print(python.course_name) # python
# print(python.course_period) # 5mio
# print(python.course_price) # 1000
class Student(People):
school = 'SH'
def __init__(self,name,age,gender,course_name,course_period,courses_price,course=None):
if course is None:
self.course = []
self.course = course
super().__init__(name,age,gender)
# Course.__init__(self,course_name,course_period,courses_price)
def choose_course(self,course):
self.course.append(course)
print('%s选课成功%s'%(self.name,self.course))
stu = Student('meng',18,'male','python','5mio',2000)
# course = ['python','linux']
# stu.course.append(python.course_name)
# print(stu.course)
# stu.course.append(python)
# stu.course.append(linux)
# 让所有选择的课程打印出来
# for i in stu.course:
# print(i.course_name)
class Teachar(People):
school = 'SH'
def __init__(self,name,age,gender,level = None):
self.level = level
super().__init__(name,age,gender)
def score(self,stu_obj,score):
stu_obj.score = score
print('%s给%s打了%s分'%(self.name,stu_obj.name,score))
tea = Teachar('meng',18,'male')
tea.course = python
print(tea.course.course_name)
二、mixins机制
1. 分主类和辅类
2. 命名方式一般以 Mixin, able, ible 为后缀
3. 辅类位置一般在主类的左边
class Vehicle: # 交通工具
def run(self):
pass
def run1(self):
pass
def run2(self):
class FlyMixin():
# class Flyable():
def fly(self):
'''
飞行功能相应的代码
'''
print("I am flying")
class CivilAircraft(FlyMixin, Vehicle): # 民航飞机
pass
class Helicopter(FlyMixin, Vehicle): # 直升飞机
pass
class Car(Vehicle): # 汽车并不会飞,但按照上述继承关系,汽车也能飞了
pass
import socketserver
三、内置函数
1.__init__函数:
总结__init__方法
'''
1、会在调用时自动触发执行,用来为对象初始化自己独有的数据
2、__init__内应该存放是为对象初始化属性的功能,但是是可以存放任意其他代码,
想要在类调用时就立刻执行的代码都可以放到该方法内
3、__init__方法必须返回None
'''
2.__str__函数:
总结__str__方法
'''
1. 打印对象会自定触发的函数,方法
2. 返回值必须是字符串类型
'''
例子:
class People:
school = 'SH'
# 1. 打印对象会自定触发的函数,方法
# 2. 返回值必须是字符串类型
def __str__(self):
return self.school
stu = People()
print(stu)
3.__del__函数:
总结__del__方法:
'''
1. 删除对象属性的时候,自动触发
2. 当所有代码执行完成之后,还会自动触发
'''
class People:
school = 'SH'
def __init__(self):
self.f = open('xxx',mode='w')
# 1. 删除对象属性的时候,自动触发
# 2. 当所有代码执行完成之后,还会自动触发
def __del__(self):
print('__del__')
self.f.close() # 可以自己执行
stu = People()
# stu.x = 1
# del stu.x
# print(stu)
print('=====>end')
4.判断类型的方法:isinstance
例子1:
s = 'abc'
print(type(s) is str) # True
print(isinstance(s,str)) #True
例子2:issubclass
class Foo:
pass
print(issubclass(Foo, object)) # 判断是FOO的子类,True
5.__getattr__、__setattr__、__delattr__函数
例子:
class Foo:
x = 1
def __init__(self, y):
self.y = y
# 当访问一个不存在的属性时候,会自定触发
def __getattr__(self, item):
print('----> from getattr:你找的属性不存在')
def __setattr__(self, key, value):
print('----> from setattr')
# print(key)
# print(value)
# self.key = value # 这就无限递归了,你好好想想
self.__dict__[key] = value # 应该使用它
def __delattr__(self, item):
print('----> from delattr')
# del self.item #无限递归了
self.__dict__.pop(item)
obj = Foo(10)
obj.z = 10
6.__call__函数(后面框架会用到)
总结__call__:当给对象加括号时候,自定触发的函数
例子:# 必须掌握
#################################__call__###########################
class Foo:
def __init__(self):
pass
# 当给对象加括号时候,自定触发的函数
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 执行 __init__
obj()
# obj.x = 1
# obj.'x' = 1
四、反射
1.getattr:在类里找不到属性,会返回第三个值
例子:
class People:
school = 'SH'
obj = People()
x = input('>>>').strip()
print(getattr(obj,x))
print(getattr(obj,'school','aa')) # 在类里找不到属性,会返回第三个值
输出结果:SH
2.setattr:字符串形式设置属性
例子:
class People:
school = 'SH'
obj = People()
setattr(obj,'y',10) # 输出结果为字典
print(obj.__dict__)
输出结果:{'y': 10}
3.dalattr:在类里面删除属性
例子:
class People:
school = 'SH'
obj = People()
dalattr(People,'school')
print(People,__dict__)
4.hasattr:如何判断是否有这个属性
例子1:
class People:
school = 'SH'
obj = People()
print(hasattr(obj,'school'))
输出结果:True
五、异常
# 什么是异常?
异常就是错误发生额的信号, 如果不对该信息进行处理, 那么, 之后的代码就不会运行
具体来说:
1. 语法错误
# SyntaxError:
print(123
2. 逻辑错误
# 有些逻辑错误可以尽量写到完美
NameError(未定义): name 'x' is not defined
IndexError(索引错误)
AttributeError(属性错误)
TypeError(类型错误)
# 为什么用异常?
为了增强代码的健壮性
# 怎么用异常?
try:
被监测的代码1
被监测的代码2
被监测的代码3
被监测的代码4
被监测的代码5
except 异常错误1 as e:
pass
except 异常错误2 as e:
pass
except 异常错误3 as e:
pass
else:
print("当被检测的代码没有异常的时候触发")
finally:
print("不管有咩有异常,都会走")
# 也可以抛出错误
a = [1,2,3]
if len(a) >= 5:
print(123)
else:
raise Exception('索引错误')
# 断言
a = [1,2,3]
assert len(a) == 5
2.限制子类的方法,除了ABC内置模块还有一种方法
class Animal():
def speak(self):
raise Exception("必须实现speak方法")
class People(Animal):
pass
obj = People()
obj.speak()
3.自定义异常类
# 自定义异常类
class MyException(BaseException):
def __init__(self,msg):
self.msg = msg
def __str__(self):
return self.msg
raise MyException('自定义异常类')