组合和多态(继承父类,抽象类,鸭子类型)

组合

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))
posted on 2019-10-13 15:32  jueyuanfengsheng  阅读(415)  评论(0编辑  收藏  举报