Python之面向对象的组合、多态、菱形问题、子类中重用父类的两种方式

一、组合

‘‘‘
1、什么是组合
    组合就是一个类的对象具备某一个属性,该属性的值是指向另外一个类的对象

2、为何用组合
    组合也是用来解决类与类直接代码冗余问题的

3、如何用组合

‘‘‘
# 继承减少代码冗余,但是将类与类进行了强耦合,python不崇尚,所以能不用继承就尽量不用继承
class OldboyPeople:
    school = ‘oldboy‘

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

class OldboyStudent(OldboyPeople):
    def __init__(self,name,age,sex,stu_id):
        OldboyPeople.__init__(self,name,age,sex)
        self.stu_id=stu_id

    def choose_course(self):
        print(‘%s is choosing course‘ %self.name)

class OldboyTeacher(OldboyPeople):

    def __init__(self, name, age, sex, level):
        OldboyPeople.__init__(self,name,age,sex)         #重用父类中的属性(功能)(减少代码冗余)------普通的函数传参,该传几个参数传几个参数
        self.level=level

    def score(self,stu,num):          #老师有修改学生成绩的功能,所以将学生对象和修改的成绩传入
        stu.score=num
        print(‘老师[%s]为学生[%s]打分[%s]‘ %(self.name,stu.name,num))

stu1=OldboyStudent(‘猪哥‘,19,‘male‘,1)
tea1=OldboyTeacher(‘egon‘,18,‘male‘,10)

stu1.choose_course()          #学生对象选择课程------猪哥 is choosing course
tea1.score(stu1,100)          #对象的绑定方法--------老师[egon]为学生[猪哥]打分[100]
print(stu1.__dict__)          #查看学生的字典属性----{‘name‘: ‘猪哥‘, ‘age‘: 19, ‘sex‘: ‘male‘, ‘stu_id‘: 1, ‘score‘: 100}

# #定制课程类
class Course:                 #将学生和老师对象都有课程属性,所以将他们都有的属性抽出来,重新定义了一个课程类
    def __init__(self,name,period,price):           #调用类时自动触发
        self.name=name
        self.period=period
        self.price=price
    # 查看课程信息
    def tell_info(self):
        msg="""
        课程名:%s
        课程周期:%s
        课程价钱:%s
        """ %(self.name,self.period,self.price)
        print(msg)
#定制人类--------老师和学生类都是人类
class OldboyPeople:
    school = ‘oldboy‘
    # 定制人类独有的数据属性
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

class OldboyStudent(OldboyPeople):
    def __init__(self,name,age,sex,stu_id):
        OldboyPeople.__init__(self,name,age,sex)     #类直接点类体代码的函数属性,在子类中重用父类功能,就是一个普通的函数
        self.stu_id=stu_id                           #子类派生出自己独有的数据属性

    def choose_course(self):                         #子类派生出自己独有的数据属性
        print(‘%s is choosing course‘ %self.name)

class OldboyTeacher(OldboyPeople):

    def __init__(self, name, age, sex, level):
        OldboyPeople.__init__(self,name,age,sex)     #子类重用父类中的方法
        self.level=level                             #子类中派生出自己独有的属性

    def score(self,stu,num):                         #子类派生出自己独有的函数属性
        stu.score=num
        print(‘老师[%s]为学生[%s]打分[%s]‘ %(self.name,stu.name,num))

# 创造课程----------------------------------对象
python=Course(‘python全栈开发‘,‘5mons‘,3000)         #调用课程对象,产生课程对象,并自动触发__init__函数的执行
linux=Course(‘linux运维‘,‘5mons‘,800)
# python.tell_info()    #课程对象直接绑定课程类下的方法,并将课程对象当做第一个对象自动传入
# linux.tell_info()

# 创造学生与老师-----------------------------对象
stu1=OldboyStudent(‘猪哥‘,19,‘male‘,1)
tea1=OldboyTeacher(‘egon‘,18,‘male‘,10)

# 重点
# 将学生、老师与课程对象关联/组合-------------将对象之间进行关联
# --------------------------关键-----------------------------------------------
stu1.course=python          #---------------将学生对象stu1与课程对象python关联
tea1.course=linux           #---------------将老师对象stu1与课程对象linux关联
# --------------------------关键-----------------------------------------------
‘‘‘组合就是一个类的对象具备某一个属性,该属性的值是指向另外一个类的对象‘‘‘
# 即学生类产生的学生对象具备课程的属性,该课程的属性值是指向课程类中的课程对象的

stu1.course.tell_info()     #--------------等价于python.tell_info(),会打印出学生的课程信息
tea1.course.tell_info()     #--------------等价于linux.tell_info(),会打印出老师的课程信息

二、菱形继承问题

#coding:utf-8
‘‘‘
1、菱形继承
    当一个子继承多个父类时,多个父类最终继承了同一个类,称之为菱形继承

2、菱形继承的问题:
    python2区分经典类与新式类,如果子的继承是一个菱形继承,那么经典类与形式的区别为?
        经典类下查找属性:深度优先查找-----------------一条道走到黑
        新式类下查找属性:广度优先查找------------------最后才去找菱形的端点
‘‘‘

class G(object):
    # def test(self):
    #     print(‘from G‘)
    pass

class E(G):
    # def test(self):
    #     print(‘from E‘)
    pass

class B(E):
    # def test(self):
    #     print(‘from B‘)
    pass

class F(G):
    # def test(self):
    #     print(‘from F‘)
    pass

class C(F):
    # def test(self):
    #     print(‘from C‘)
    pass

class D(G):
    # def test(self):
    #     print(‘from D‘)
    pass

class A(B,C,D):
    def test(self):
        print(‘from A‘)
    # pass

obj=A()
#C3算法只试用新式类,经典类不适用
print(A.mro())  #mro是一种C3算法,[<class ‘__main__.A‘>, <class ‘__main__.B‘>, <class ‘__main__.E‘>, <class ‘__main__.C‘>, <class ‘__main__.F‘>, <class ‘__main__.D‘>, <class ‘__main__.G‘>, <class ‘object‘>]
obj.test()       #A->B->E-C-F-D->G-object-------对象属性的查找会严格按照mro列表的顺序进行查找

三、在子类派生的新方法中重用父类功能的另种方式

# 在子派生的新方法中重用父类功能的两种方式
# 方式一:与继承无关
#指名道姓法,直接用:类名.函数名
class OldboyPeople:
    school = ‘oldboy‘
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

class OldboyStudent(OldboyPeople):
    def __init__(self,name,age,sex,stu_id):
        OldboyPeople.__init__(self,name,age,sex)      #-------(减少代码冗余)指名道姓法,直接用:类名.函数名,按照函数传参的规则进行传参即可
        self.stu_id=stu_id                            #子类派生出自己独有的数据属性

    def choose_course(self):                          #子类派生出自己的函数属性
        print(‘%s is choosing course‘ %self.name)

# 方式二:严格以mro列表继承属性查找关系
# super()会得到一个特殊的对象,该对象就是专门用来访问父类中的属性的(按照继承的关系)
# super().__init__(不用为self传值)------------可以理解为super()是一个特殊的对象,所以对象绑定方法有一个自动传值的效果
# 注意:
# super的完整用法是super(自己的类名,self),在python2中需要写完整,而python3中可以简写为super()
class OldboyPeople:
    school = ‘oldboy‘

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

class OldboyStudent(OldboyPeople):
      # 定制学生类的数据属性,在定制数据属性的过程中,重用了父类中的数据属性
    def __init__(self,name,age,sex,stu_id):
        # OldboyPeople.__init__(self,name,age,sex)         #------父类功能重用方法一
        super(OldboyStudent,self).__init__(name,age,sex)   #------父类功能重用方法二
        self.stu_id=stu_id
    #定制学生类的函数属性
    def choose_course(self):
        print(‘%s is choosing course‘ %self.name)

stu1=OldboyStudent(‘猪哥‘,19,‘male‘,1)
print(stu1.__dict__)  #-------查看学生对象的字典属性,{‘name‘: ‘猪哥‘, ‘age‘: 19, ‘sex‘: ‘male‘, ‘stu_id‘: 1}
print(OldboyStudent.mro()) #------查看学生类的继承关系,[<class ‘__main__.OldboyStudent‘>, <class ‘__main__.OldboyPeople‘>, <class ‘object‘>]

# 继承顺序查找再应用:
class A:
    def f1(self):
        print(‘A.f1‘)
class B:
    def f2(self):
        super().f1()         #B类和A类没有继承关系,但是会按照mro列表,从该类的下一个类继续进行查找,即此时会到A中进行查找
        print(‘B.f2‘)

class C(B,A):
    pass

obj=C()
print(C.mro()) #C-》B->A->object,查看C类的继承关系,[<class ‘__main__.C‘>, <class ‘__main__.B‘>, <class ‘__main__.A‘>, <class ‘object‘>]
obj.f2()       #对象属性的查找会严格按照mro列表的顺序进行查找,自己的对象没有到自己的类中找,自己的类中没有,到父类中找,此时父类查找的先后顺序就是按照mro列表来的

# 打印结果:
‘‘‘
A.f1
B.f2
‘‘‘

四、多态与多态性

‘‘‘
1 什么是多态
    多态指的是同一种事物的多种形态
        水-》冰、水蒸气、液态水
        动物-》人、狗、猪

2 为和要用多态
    多态性:
    继承同一个类的多个子类中有相同的方法名
    那么子类产生的对象就可以不用考虑具体的类型而直接调用功能

3 如何用
‘‘‘
import abc
class Animal(metaclass=abc.ABCMeta): #定义一个抽象类,规范一个类的类
    @abc.abstractmethod              #装饰器装饰后,意味着但凡继承类该类的方法,函数属性的属性名都必须与父类的函数属性名一致,否则就会报错
    def speak(self):
        pass
    @abc.abstractmethod
    def eat(self):
        pass

# Animal() #强调:父类是用来制定标准的,不能被实例化-------此时实例化就会报错,这并不是python崇尚的,python更多的是一种约定俗成的,而不是硬性的限制
class People(Animal):
    def speak(self):
        print(‘say hello‘)

    def eat(self):
        pass

class Dog(Animal):
    def speak(self):
        print(‘汪汪汪‘)

    def eat(self):
        pass
class Pig(Animal):
    def speak(self):
        print(‘哼哼哼‘)

    def eat(self):
        pass

peo1=People()
dog1=Dog()
pig1=Pig()
#
#继承同一个动物类的多个子类(人、狗、猪类)中有相同的方法名(speak\eat),那么子类产生的对象就可以不用考虑具体的类型而直接调用功能
peo1.speak()      #不用考虑具体的对象类型,而直接调用speak的功能
dog1.speak()
pig1.speak()

# -----------------------不用考虑是什么动物来调用speak的函数属性,所以将其封装成一个功能-----------------------------------
def my_speak(animal):
    animal.speak()
my_speak(peo1)
my_speak(dog1)
my_speak(pig1)
# -----------------------不用考虑是什么动物来调用speak的函数属性,所以将其封装成一个功能-----------------------------------

# 不同的数据类型,他们都有统计长度的这个方法,所以我们想到的是将他们制定成一套方法,便于对不同的数据类型进行统计
l=[1,2,3]
s=‘helllo‘
t=(1,2,3)

print(l.__len__())          #用同一种形式去调用的好处就是将其功能封装成一个函数时,只需要传入对象就可以了
print(s.__len__())          #如果用不同的方法名去统计不同数据类型的长度,这样封装成函数时就需要制定不同的函数去封装
print(t.__len__())

# def len(obj):
#     return obj.__len__()

print(len(l)) # l.__len__()
print(len(s)) #s.__len__()
print(len(t))

# python推崇的是鸭子类型,只要你叫的声音像鸭子,并且你走路的样子也像鸭子,那你就是鸭子
class Disk:
    def read(self):
        print(‘disk read‘)

    def write(self):
        print(‘disk wirte‘)

class Process:
    def read(self):
        print(‘process read‘)

    def write(self):
        print(‘process wirte‘)

class File:
    def read(self):
        print(‘file read‘)

    def write(self):
        print(‘file wirte‘)

obj1=Disk()
obj2=Process()
obj3=File()

obj1.read()
obj1.write()

原文地址:https://www.cnblogs.com/sui776265233/p/9234603.html

时间: 2024-11-09 20:46:26

Python之面向对象的组合、多态、菱形问题、子类中重用父类的两种方式的相关文章

javascript消除字符串两边空格的两种方式,面向对象和函数式编程

主要是javascript中消除字符串空格,比较两种方式的不同 //面向对象,消除字符串两边空格 String.prototype.trim = function() { return this.replace(/(^\s*)|(\s*$)/g, ""); }; //去左右空格的函数; function trim(s){ return s.replace(/(^\s*)|(\s*$)/g, ""); }调用消除空格的两种方式. var defualtPhone =

day2-操作系统,编程语言分类,执行Python程序的两种方式,变量,python的内存管理,

1    什么是操作系统 操作系统位于计算机与应用软件之间,是一个协调,管理,控制计算机硬件资源与软件资源的控制程序 2     为何要有操作系统? 1,控制硬件. 2,把对硬件的复杂的操作封装成优美简单的接口,给用户或者应用程序去使用 注意:一套完整的计算机系统包含三部分 应用程序:比如QQ,暴风影音 操作系统:比如windows linux unix 计算机硬件 强调:我们以后开发的都是应用程序,应用程序无法直接操作硬件,但凡要操作硬件,都是调用操作系统的接口 3 编程语言的分类 1,机器语

操作系统,编程语言分类,执行python两种方式,变量,内存管理,定义变量的三个特征

操作系统 1.什么是操作系统 操作系统位于计算机硬件与应用软件之间 是一个协调.管理.控制计算机硬件资源与软件资源的控制程序 2.为何要有操作系统? 1.控制硬件 2.把对硬件的复杂的操作封装成优美简单的接口(文件),给用户或者应用程序去使用 注意:一套完整的计算机系统包含三部分 应用程序:qq,暴风影音,快播 操作系统:windows,linux,unix 计算机硬件 强调: 我们以后开发的都是应用程序 应用程序无法直接操作硬件,但凡要操作硬件,都是调用操作系统的接口 编程语言分类 1.机器语

python中字符串链接的七种方式

一. str1+str2 string类型 '+'号连接 >>> str1="one" >>> str2="two" >>> str1+str2 'onetwo' >>>注意:该方式性能较差,因为python中字符串是不可变的类型,使用 + 连接两个字符串时会生成一个新的字符串,生成新的字符串就需要重新申请内存,当连续相加的字符串很多时(a+b+c+d+e+f+...) ,效率低下就是必然的了例

Python 引入包的两种方式区别

1.import XXX仅仅是告诉我们需要使用这个包,但是你真正使用的时候,需要完整的导入这个包的全路径 比如: import wechat.views 在使用其中的hello函数的时候,需要 wechat.views.hello - 这个路径不能简略 2.from ... import ...就不需要指定父的路径了 比如: from wechat.views import *    #你可以使用views内部的变量 你就可以直接使用其中的hello hello 但是如果: from wecha

python中package机制的两种实现方式

当执行import module时,解释器会根据下面的搜索路径,搜索module1.py文件. 1) 当前工作目录 2) PYTHONPATH中的目录 3) Python安装目录 (/usr/local/lib/python) 事实上,模块搜索是在保存在sys.path这个全局变量中的目录列表中进行搜索. sys.path会在解释器开始执行时被初始化成包含: 1)当前工作目录 2) PYTHONPATH中的目录 3) Python安装目录 (/usr/local/lib/python) pack

python用requests和urllib2两种方式调用图灵机器人接口

最近从网上看见个有意思的图灵机器人,可以根据不同的信息智能回复,比如你发送一个"讲个笑话",它就会给你回复一个笑话,或者"北京天气"就可以回复天气情况,或者英文单词然后给你回复中文释义.官方文档中有php和java的调用方式,我就弄个python的吧. 注册获取API KEY 这一步很简单,直接注册一个账号就可以看到你的API KEY.这个KEY我们以后发送get请求的时候需要用到. Pythoh调用示例 掉用也比较简单,主要是模拟post 请求.然后解析 json

Python实现屏幕截图的两种方式

Python实现屏幕截图有两种方式: 使用windows API 使用PIL中的ImageGrab模块 下面对两者的特点和用法进行详细解释. 一.Python调用windows API实现屏幕截图 好处是 灵活 速度快 缺点是: 写法繁琐 不跨平台 import time import win32gui, win32ui, win32con, win32api def window_capture(filename): hwnd = 0 # 窗口的编号,0号表示当前活跃窗口 # 根据窗口句柄获取

python中执行shell的两种方法总结

这篇文章主要介绍了python中执行shell的两种方法,有两种方法可以在Python中执行SHELL程序,方法一是使用Python的commands包,方法二则是使用subprocess包,这两个包均是Python现有的内置模块.需要的朋友可以参考借鉴,下面来一起看看吧. 一.使用python内置commands模块执行shell commands对Python的os.popen()进行了封装,使用SHELL命令字符串作为其参数,返回命令的结果数据以及命令执行的状态: 该命令目前已经废弃,被s