组合和多态(继承父类,抽象类,鸭子类型)
目录
组合
1.什么是组合
组合指的是某一个对象拥有一个属性,该属性的值是另外一个类的对象
class Foo:
pass
class Bar:
pass
obj=Foo()
obj.attr=Bar()
obj.xxx
obj.attr.yyy
2. 为何要用组合
通过为某一个对象添加属性(属性的值是另外一个类的对象)的方式,可以间接地将两个类关联/整合/组合到一起,从而减少类与类之间代码冗余
class Foo1:
pass
class Foo2:
pass
class Foo3:
pass
class Bar:
pass
obj_from_bar=Bar()
obj1=Foo1()
obj2=Foo2()
obj3=Foo3()
obj1.attr1=obj_from_bar
obj2.attr2=obj_from_bar
obj3.attr3=obj_from_bar
3.组合使用场景
组合与继承都是有效地利用已有类的资源的重要方式。但是二者的概念和使用场景皆不同,
1.继承的方式
通过继承建立了派生类与基类之间的关系,它是一种'是'的关系,比如白马是马,人是动物。
当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如老师是人,学生是人
2.组合的方式
用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python和linux课程,教授有学生s1、s2、s3...
当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好
4 .组合使用示例
class People:
school = 'Oldboy'
def __init__(self,name,age,sex,):
self.name = name
self.age = age
self.sex = sex
class Student(People):
def __init__(self, name, age, sex,score=0):
People.__init__(self,name,age,sex)
self.score = score
def choose_course(self):
print('%s choosing course' % self.name)
class Teacher(People):
def __init__(self,name,age,sex,level):
People.__init__(self,name,age,sex)
self.level=level
def score(self,stu,num):
stu.score=num
class Course:
def __init__(self,c_name,c_price,c_period):
self.c_name = c_name
self.c_price = c_price
self.c_period = c_period
def tell_info(self):
print('<课程名:%s 价钱:%s 周期:%s>' %(self.c_name,self.c_price,self.c_period))
# 创建课程对象
python=Course('python全栈开发',1900,'5mons')
linux=Course('linux架构师',900,'3mons')
stu1=Student('刘二蛋',38,'male')
stu1.course=python
# print(stu1.__dict__)
stu1.course.tell_info()
tea1=Teacher('zhang',18,'male',10)
tea1.course=python
# print(tea1.__dict__)
tea1.course.tell_info()
多态
1.多态的定义:
多态指的是同一种事物的多种形态
2.多态的目的:
多态也称之为多态性,在程序中继承就是多态的表现形式。
多态的目的是为了让多种不同类型的对象,在使用相同的功能(方法)的情况下,都 能做出不同的响应。
父类:定义一套统一的标准,
子类:遵循父类统一的标准。
多态的最终目的:统一子类编写规范,为了让使用者更方便调用相同功能的方法。而 多态的精髓就在于统一。
3.如何实现多态
1.继承父类
class Animal: # 父类定义一套统一的标准,不是为了实现某一具体功能,具体实现功能还是要继承的那些子类,这样使用者只需要学习父类的一套标准就行了。
def eat(self):
pass
def drink(self):
pass
def speak(self):
pass
# print('我们一起喵喵喵。。。。')
# 猪
class Pig(Animal):
# 吃
def eat(self):
print('猪在吃饭')
pass
# 喝
def drink(self):
pass
def speak(self):
# super().speak()
print('哼哼哼~~~')
# 猫
class Cat(Animal):
# 吃
def eat(self):
print('猫在吃饭')
# 喝
def drink(self):
pass
def speak(self):
print('喵喵喵~~')
# 狗
class Dog(Animal):
# 吃
def eat(self):
print('狗在吃饭')
# 喝
def drink(self):
pass
def speak(self):
print('汪汪汪~~~')
pig = Pig()
cat = Cat()
dog = Dog()
pig.speak()
cat.speak()
dog.speak()
2.抽象类
注意,在Python中不会强制要求子类必须遵循父类的一套标准,所以如果要强制子类遵循父类的一套标准,那么就要使用抽象类。
1.是什么?
导入 abc(abstract_class)模块
2.使用的目的?
强制子类必须遵循父类的一套标准
3.如何使用?
import abc
import abc
class Animal(metaclass=abc.ABCMeta):
# 吃
@abc.abstractmethod
def eat(self):
pass
# 喝
@abc.abstractmethod
def drink(self):
pass
# 叫
@abc.abstractmethod
def speak(self):
pass
# Animal() # 父类只是用来建立规范的,不能用来实例化,更无须实现内部的方法。会报错
# 猪
class Pig(Animal): # 子类在继承父类时,就必须遵循父类制定的规范,即遵守父类内部定义的抽象类方法,否则就报错
# 吃
def eat(self):
print('猪在吃饭')
pass
# 喝
def drink(self):
pass
def speak(self):
print('哼哼哼~~~')
# 派生
def run(self):
pass
pig = Pig()
3.鸭子类型(不推荐强制遵循父类的标准)
鸭子类型:在不知道当前对象是何物的情况下,但你长得像鸭子,那你就是鸭子。
注意:在Python中,不会强制要求子类必须遵循父类的一套标准,所以出现了鸭子类型。
# python崇尚鸭子类型
class Disk:
def read(self):
print('Disk read')
def write(self):
print('Disk write')
class Memory:
def read(self):
print('Mem read')
def write(self):
print('Mem write')
class Cpu:
def read(self):
print('Cpu read')
def write(self):
print('Cpu write')
obj1=Disk()
obj2=Memory()
obj3=Cpu()
# 方式1
obj1.read()
obj2.read()
obj3.read()
# 方式2
def READ(obj):
obj.read()
for obj in (obj1,obj2,obj3):
READ(obj)
4.实现多态的三种方式的优缺点
继承(继承父类或者抽象类):耦合性太高,扩展性差;
鸭子类型:耦合度低,程序的可扩展性强;
5.容器数据类型与多态之间的联系
str,list,tuple,dict,set
# 以列表类型,
l = [1,2,3,4] # l是内置类list的一个实例,即对象,通过对象点的方式可以对操作对象类中的方法(内置函数)
l.append(99) # 对象(l).方法(append),对象绑定方法
print(l) # [1, 2, 3, 4, 99]
list.append(l,100) # 类绑定方法,就是普通函数,需将对象作为第一个参数传入
print(l) # [1, 2, 3, 4, 99, 100]
print(l.__class__) # <class 'list'>
print(l.__class__.__dict__) # 获取list类名称空间的名字(即list的内置方法)
print(l.__class__.__name__) # list
总结:容器数据类型,赋值给一个变量名,这个变量名就是对象,变量名点内置方法就是点对应类里面的方法(技能)。
示例
#其实大家一直在享受着多态性带来的好处,比如Python的序列类型有多种形态:字符串,列表,元组,多态性体现如下
#str,list,tuple都是序列类型
s=str('hello')
l=list([1,2,3])
t=tuple((4,5,6))
#我们可以在不考虑三者类型的前提下使用s,l,t
s.__len__()
l.__len__()
t.__len__()
str1 = '1234'
list1 = [1, 2, 3]
def LEN(d):
return d.__len__()
print(LEN(str1))
print(LEN(list1))
print(len(str1))
print(len(list1))