zoukankan      html  css  js  c++  java
  • 继承,组合

    继承

    什么是继承

    继承是一种关系: 描述两个类之间 什么是什么的关系

    例: 麦兜,佩奇,猪悟能 都是猪

    在程序中,继承描述的是类与类之间的关系

    例如:a继承了b,a就能直接舒勇b已经存在的属性方法

    a称为子类,b称为父类(基类)

    为什么要使用继承:

    继承的一方(子类)可以直接使用被继承一方(父类)已经有的东西(属性和方法)

    目的: 重用已有的代码,提高重用性

    如何使用:

    语法:

    class 类名称(父类1名称,父类2名称,...)
        代码块
    # python中,一个子类可以同时继承多个父类

    例:

    class Sup:
        info = 'from Sup'
        def money(self):
            print('from Sup money')
    ​
    class Sub(Sup):  # Sub 继承 Sup
        pass
    obj = Sub()
    # 子类调用父类中的属性
    print(obj.info)  # >>> from Sup
    # 子类调用父类中的方法
    obj.money()  # >>> from Sup money

    抽象:

    名词解释:不具体,看不清,很模糊,看不懂

    抽象的过程:

    1.将多个类中相同的部分(属性或方法),进行抽取,

    2.创建一个新的类,把这些相同的部分放到新的类中(这个新类是被抽取的类的大类,)

    正确的使用继承:

    1.先抽象再继承

    2.继承一个已经存在的类,扩展或修改原始功能

    图解:

    例:老师类和学生类相同的部分有name,age,gender...,老师和学生都属于人,就可以创建一个新类:人类

    class Teacher:
        func = 'teach'
        def __init__(self, name, age, gender):
            self.name = name
            self.age = age
            self.gender = gender
    ​
        def say_hi(self):
            print('name:%s, age:%s, gender:%s'%(self.name, self.age, self.gender))
    ​
    t = Teacher('haha', 20, 'male')
    print(t.func)
    t.say_hi()
    ​
    ​
    class Student:
        func = 'play'def __init__(self, name, age, gender):
            self.name = name
            self.age = age
            self.gender = gender
    ​
        def say_hi(self):
            print('name:%s, age:%s, gender:%s' % (self.name, self.age, self.gender))
    ​
    s = Student('xixi', 15, 'male')
    print(s.func)
    s.say_hi()
    ​
    # 抽象后的到:
    ​
    ​
    class Person:
        def __init__(self, name, age, gender):
            self.name = name
            self.age = age
            self.gender = gender
        def say_hi(self):
            print('name:%s, age:%s, gender:%s' % (self.name, self.age, self.gender))
    ​
    ​
    class Teacher(Person):
        func = 'teach'
        def skill_training(self):
            print('教 Python 代码')
            
    t = Teacher('haha', 20, 'male')
    print(t.func)  # >>> teach
    t.say_hi()  # >>> name:haha, age:20, gender:male
    t.skill_training()  # >>> 教 Pythong 代码
    class Student(Person):
        func = 'play'
    ​
    s = Student('xixi', 15, 'male')
    print(s.func)  # >>> play
    s.say_hi()  # >>> name:xixi, age:15, gender:male

    属性的查找顺序

    对象自己 ---> 所在类 ---> 父类 ---> Object

    class A:
        func = 'haha'
    class B(A):
        func = 'xixi'
    obj = B()
    obj.func = 'hehe'
    print(obj.func)  # >>> hehe

    派生

    当一个子类中出现了父类中不同的内容(属性或方法)时,这个子类就称之为派生类

    通常子类都会写一些新的代码,不会和父类完全相同,即通常同时派生类

    class sup:
        text = 20
        def func(self):
            print('hello')
    class sub(sup):
        def auth(self):
            print('hello, world')

     

    覆盖

    也称之为重写 overrides

    当子类中出现了与父类中 名称 完全一致的属性会方法

    父类中被覆盖的属性会方法子类无法再调用,因为查找顺序:对象-->子类-->父类

    class sup:
        text = 20
        def func(self):
            print('hello')
    class sub(sup):
        # 覆盖父类中的func函数
        def func(self):
            print('hello, world')

    练习 : 创建一个可以限制元素类型的列表*

    # 把list当做父类,可以使用list中已经写好的代码,不需要再重新写
    class MyList(list):
        def __init__(self, my_type):
            # 调用父类的初始化方法,来完成基本的初始化
            super().__init__()  # 因父类的init方法不需要参数,所以不用传参
            self.my_type = my_type
    ​
        def append(self, obj):
            '''
            :param obj:  要添加的元素
            :return: 没有返回值
            '''
            if type(obj) == self.my_type:
                # 调用父类(list)里的append方法,来完成真正的存储工作
                super(MyList, self).append(obj)
                # 也可用 super().append(obj)
            else:
                print('添加的元素类型与设定的%s类型不同'%self.my_type)
    ​
    # 当你的需求是在创建对象时干点什么事,就该想到__init__初始化方法
    m = MyList(int)  # 元素定义为 int 类型
    m.append(2)
    m.append(4)
    m.append(6)
    print(m)  # >>> [2, 4, 6]
    print(m[1])  # 4
    m.append('1')  # 添加的元素类型与设定的<class 'int'>类型不同

    在子类中访问父类的内容

    语法:

    方式1:
       super(当前类名,self).要调用的父类的属性或方法
    方式2:
       super().要调用的父类的属性或方法
       # 方式2 属于python3语法
    方式3:
       父类名.要调用的父类的属性或方法(self)
       # 方式3余继承无关
    class Animal:
        def __init__(self, name, age, hp):
            self.name = name
            self.age = age
            self.hp = hp
    
        def eat(self):
            print('吃药回血')
    
    class Dog(Animal):
        def __init__(self, name, age, hp, colour):
            # 调用父类的__init__ 方法一:
            Animal.__init__(self, name, age, hp)
            # 调用父类的 __init__ 方法二:
            super().__init__(name, age, hp)
            self.colour = colour  # 派生属性
    
        def eat(self):
            print('吃药回蓝')
    d = Dog('二哈', 2, 100, 'black')
    d.eat()  # 吃药回蓝
    super(Dog, d).eat()  # 吃药回血
     

    注意(**)

    当你继承一个现有的类,并且你覆盖了父类中的双下init方法时,必须在初始化方法的第一行调用父类的初始化方法,并传入父类所需要的参数

    class Person:
        def __init__(self,name,gender,age,*args):
            self.name = name
            self.gender = gender
            self.age = age
            self.aa()  # 会执行此函数
    def aa(self):
            print("aa run")
    ​
        def say_hi(self):
            print("name:%s ,gender:%s,age:%s" % (self.name,self.gender,self.age))
    ​
    ​
    class Student(Person):
        # 覆盖父类的 __init__ 
        def __init__(self,name,gender,age,number):
            # 调用父类的 __init__ 并传参
            super().__init__(name,gender,age)
            self.number= number
    ​
        def say_hi(self):
            # 调用父类方法
            super().say_hi()
            print("numnber:%s" % self.number)
    ​
    stu = Student("rose","mael",20,"01")
    stu.say_hi()
    >>>
    aa run
    name:rose ,gender:mael,age:20
    numnber:old01

    组合

    组合是一种关系 : 描述两个类之间 什么有什么的关系

    例 : 学生有手机,游戏角色有装备...

    将一个类的对象作为另一个类的属性传入

    什么时候使用继承: 分析两个类之间的关系,到底是不是 什么是什么的关系

    什么时候使用组合: 分析两个类之间的关系, 没有太大的关系,完全不属于同类

    组合比继承的耦合性更低

     

    菱形继承

    首先声明 Python 支持多继承 可以通过 子类名.mro() 查看父类的查找顺序,返回的是一个列表

    新式类与经典类

    python3中的任何类型都是直接或间接的继承Object

    新式类: 任何显式或隐式地继承自Object的类就称之为新式类,python3中都是新式类

    经典类:既不是Object的子类,仅在python2中出现

    菱形继承时

    1新式类,先查找深度,当遇到了共同的父类时就查找广度

    2.经典类: 按深度查找

     

     

    练习:

    """
    程序员
    姓名 性别 年龄 工资 编程技能
    和项目经理
    多了奖金,管理技能
    项目经理也是程序员晋升而来
    将程序员信息和管理员信息写入文件各自的类别文件中
    """
    import os
    import pickle
    
    # 获取到 项目 的路径
    BASE_PATH = os.path.dirname(__file__)
    # 拼接 db 文件夹的路径
    DB_PATH = os.path.join(BASE_PATH,'db')
    
    class File:
    
        # 写文件功能
        def save(self):
            # 类 文件的名
            cls_name = self.__class__.__name__
            # 拼接  类文件的路径
            cls_path = os.path.join(DB_PATH,cls_name)
            # 判断  类文件是否存在
            if not os.path.exists(cls_path):
                # 若不在 创建文件夹
                os.mkdir(cls_path)
            # 拼接  类文件夹中文件的路径
            cls_name_path = os.path.join(cls_path,self.name)
            # 将 程序员 文件写入程序员文件夹中
            with open(cls_name_path,'wb') as f:
                # 序列化到文件中
                pickle.dump(self, f)
                f.flush()
    
        # 读文件功能
        def get_info(self, name):
            # 拼接 所查找的类的文件夹路径
            check_cls_path = os.path.join(DB_PATH,self.__class__.__name__)
            # 拼接 所查找的文件路径
            check_name_path = os.path.join(check_cls_path,name)
            # 判断 类文件夹下是否有此文件
            if os.path.exists(check_name_path):
                # 读出文件
                with open(check_name_path,'rb') as f:
                    res = pickle.load(f)
                    return res
    
    
    # 程序员的类
    class Coder(File):
        def __init__(self, name, gender, age, salary):
            self.name = name
            self.gender = gender
            self.age = age
            self.salary = salary
    
        # 程序员的功能
        def programming(self):
            print('正在开发项目...')
    
    # 项目经理的类 项目经理从程序员而来,属于程序员,同时又有其他功能 所以是继承
    class Manager(Coder):
        def __init__(self, name, gender, age, salary, bonus):
            super(Manager, self).__init__(name, gender, age, salary)
            self.bonus = bonus
        def manage(self):
            print('正在与程序员友好的沟通中...')
    
    c = Coder('X', 'man', 20, 100)
    c.programming()
    c.save()
    res = c.get_info('X')
    print(res)
    print(res.name)
    print(res.gender)
    print(res.age)
    print(res.salary)
    
    print('---------------------------------------------------------')
    
    m = Manager('Y', 'woman', 21, 200, 50000)
    m.manage()
    m.save()
    res = m.get_info('Y')
    print(res)
    print(res)
    print(res.name)
    print(res.gender)
    print(res.age)
    print(res.salary)
    print(res.bonus)
    答案
  • 相关阅读:
    磁盘管理之磁盘组成
    用户管理
    定时任务
    虚拟机安装centos6.9
    linux的文件属性与文件权限
    linux磁盘容量不足
    正则表达式与特殊符号
    linux三剑客与正则案例
    借用父构造函数继承属性
    myeclipse常用快捷键
  • 原文地址:https://www.cnblogs.com/waller/p/11247101.html
Copyright © 2011-2022 走看看