昨日回顾:
-继承
-如何使用
-通过继承来减少代码冗余
-如何重用父类的方法一
-属性查找顺序
-如何重用父类的方法二
-派生
今日内容:
-组合
-什么时候用组合,什么时候用继承
-什么是什么的关系用继承
-什么有什么的关系用组合
-多态和多态性
-封装
一、组合
什么是组合:对象的某个属性是另一个类的对象
# 组合的概念
class Foo:
def __init__(self, bar):
self.bar = bar
class Bar:
pass
bar = Bar()
f = Foo(bar)
# 为什么使用组合: 可以减少代码冗余
class Person:
school = 'old_boy'
class Teacher(Person):
def __init__(self, name, level, course):
self.name = name
self.level = level
# course是课程对象,表示老师教授的课程
self.course = course
class Student(Person):
def __init__(self, name, course):
self.name = name
# course是课程对象,表示学生选的课程
self.course = course
class Course:
def __init__(self, course_name, course_price):
self.course_name = course_name
self.course_price = course_price
course = Course('Python', 20000)
stu = Student('nick', course)
teacher = Teacher('nick', '高级', course)
print(stu.course.name)
print(teacher.course.name)
# 组合的应用
class Person:
school = 'oldboy'
class Teacher(Person):
def __init__(self,name,age,level,course):
self.name=name
self.age=age
self.level=level
#course是课程对象,表示老师教授的课程
self.course=course
class Student(Person):
# course=[] #错误
def __init__(self,name,age):
self.name=name
self.age=age
# course是课程对象,表示学生选的课程
self.course_list = []
def choose_course(self,course):
# self.course=[] #错误
#把课程对象追加到学生选课的列表中
self.course_list.append(course)
def tell_all_course(self):
#循环学生选课列表,每次拿出一个课程对象
for course in self.course_list:
#课程对象.name 取到课程名字
print(course.name)
class Course:
def __init__(self,course_name,course_price,course_period):
self.name=course_name
self.price=course_price
self.period=course_period
course=Course('Python',20199,7)
stu1=Student('nick',19)
stu1.choose_course(course)
stu2=Student('王二丫',19)
stu2.choose_course(course)
stu2.choose_course(Course('linux',19999,5))
二、多态与多态性
什么是多态:一类事物的多种形态
多态性:多态性是指在不考虑实例类型的情况下使用实例
好处:1. 增加了程序的灵活性。
2.增加了程序的可扩展性。
# 多态基础
class Animal:
def speak(self):
pass
class Pig(Animal):
def speak(self):
print('哼哼哼')
class Dog(Animal):
def speak(self):
print('汪汪')
class People(Animal):
def Speak(self):
print('say hello')
pig = Pig()
dog = Dog()
def animal_speak(obj):
obj.speak()
animal_speak(pig)
animal_speak(dog)
# 两种约束代码的方式
# 第一种:用abc模块实现接口统一化,约束代码(用的比较少)
# 第二种:用异常处理来实现(常用)
class Animal():
def speak(self):
#主动抛出异常
raise Exception('你得给我重写它啊')
class Pig(Animal):
def speak(self):
print('哼哼哼')
class People(Animal):
def speak(self):
print('say hello')
pig=Pig()
pe=People()
def animal_speak(obj):
obj.speak()
animal_speak(pig)
animal_speak(pe)
# 崇尚鸭子类型:只要走路像鸭子(对象中有某个绑定方法),那你就是鸭子
三、封装
封装是什么:封装就好像是拿来一个麻袋,把小猫,小狗,小王八,一起装进麻袋,然后把麻袋封上口子,然后隐藏起来,外部访问不到。
如何用代码实现隐藏:
隐藏属性/隐藏方法,隐藏之后,外部访问不到,只有内部能访问
# 隐藏属性: 通过 __变量名来隐藏
# 隐藏方法: 通过 __方法名来隐藏
# name隐藏起来,隐藏属性是为了安全
class Person:
def __init__(self, name, age):
self.__name = name
self.__age = age
def get_name(self):
print(self.__name)
p = Person('nick', 89)
print(p.age)
print(p.get_name())
# 通过变形隐藏了属性
# 隐藏的属性在python还是能够在外部访问,但是一般不这么做
print(p.__Person__name)
print(p.__dict__)
# 隐藏方法:隔离复杂度
class Person:
def __init__(self, name, age):
self.__name = name
self.__age = age
def __speak(self):
print('wangwang')
p = Person('nick', 89)
p.__speak()
print(Person.__dict__)
P._Person__speak()
# 什么时候属性变形,只要在类内部,以__变量名 命名的变量,都会被隐藏,会发生变形,在外部放 # 入的__变量名 属性是不会隐藏的
# 计算人的bmi指数
# property装饰器:把方法包装成数据属性
class Person:
def __init__(self, name, height, weight):
self.name = name
self.height = height
self.weight = weight
@property
def bmi(self):
return self.weight/(self.hetght ** 2)
p = Person('lqz', 1.82, 70)
print(p.bmi)
# property之setter和deleter
class Person:
def __init__(self,name,height,weight):
self.__name=name
self.__height=height
self.__weight=weight
@property
def name(self):
return '[我的名字是:%s]'%self.__name
#用property装饰的方法名.setter
@name.setter
def name(self,new_name):
# if not isinstance(new_name,str):
if type(new_name) is not str:
raise Exception('改不了')
if new_name.startswith('sb'):
raise Exception('不能以sb开头')
self.__name=new_name
# 用property装饰的方法名.deleter
@name.deleter
def name(self):
# raise Exception('不能删')
print('删除成功')
# del self.__name
p=Person('lqz',1.82,70)
print(p.name)
p.name = 'pppp'
p.name = 999
p.name = 'sb_nick'