• Day22 面向对象(继承封装)


    面向对象有三大特性:封装,继承,多态

    1.继承

      1 .什么是继承: 继承是一种关系,再程序中,继承描述的就是类与类之间的关系,例如A继承了B,A就可以使用B已经存在的方法和属性,A就称为是B的子类,B也就是父类,也称为基类

      2.继承的特点:继承的一方可以直接使用被继承一方已经有的方法和属性.可以重用已经有的代码.提高代码的重用性

      3:继承语法格式:

    class A:
        pass
    
    class B(A):  # B类继承了A类
        pass
    
    class C(B,A): # C类同时继承了B类与A类
        pass

      3.抽象. 再我们使用继承时不要盲目的去写要先进行抽象,抽象就是否将多个子类中相同的部分进行抽取,形成一个新的类,这个过程就时抽象

      4.继承的使用流程: 1 先抽象再继承        2,继承一个已经存在的类,扩展或时修改原始的功能

      5.属性的查找顺序:  先从对象自己本身找,然后再是自身所在类中,再找所在类的父类中查找.层层递进,最终层为Object,若找不到则报错

    class A:
        num = 1
    
    class B(A):
        num = 2
    
    
    d = B()
    d.num = 3
    print(d.num)   # 3
    class A:
        num = 1
    
    class B(A):
        num = 2
    
    
    d = B()
    print(d.num)  # 2
    class A:
        num = 1
    
    class B(A):
        # num = 2
        pass
    
    
    
    d = B()
    print(d.num)  # 1

      6.派生: 当一个子类中出现了与父类中不同的内容是,这个子类就称之为派生类,通常子类都会有一些新的代码.所以一般的子类都是派生类

      7.覆盖: 当子类出现了和父类名称完全一致的属性或方法时.子类在定义这些相同的方法的时候就会父类的这些方法进行覆盖  也称为重写overrides

      8.子类中访问父类的内容  通过super()  语法

    方式1:
    super(当前类名称,self).你要调的父类的属性或方法
    方式2:
    super().你要调的父类的属性或方法
    方式3:   # 与继承无关
    类名称.你要调的父类的属性或方法(self)  

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

      9 : 练习,实现一个可以限制元素类型的列表

    class MyList(list):
        def __init__(self):
            super().__init__()
    
    
        def append(self,name):
            if type(name) is str:
                print("不能是字符串")
            else:
                super().append(name)
    
    m = MyList()
    m.append('6666')
    print(m[0])

      10: 组合:  组合是描述两个对象什么有什么的关系,当两个类之间没有太大的关系,完全不属于同类,如果我们使用继承就不符合正常逻辑了.这是我们又需要去访问令一个类中的方法或属性,这时候我们就可以使用组合,使用组合最终目的也是提高代码的复用性,降低代码的耦合度

    class Phone:
        def __init__(self,kind,price):
            self.kind = kind
            self.price = price
        def call(self):
            print('拨号中')
    
    
    class Stu:
        def __init__(self,name,age,iphone):
            self.name = name
            self.age = age
            self.iphone = iphone
    
        def with_call(self):
            print('我要打电话')
    
    
    iphone = Phone('苹果',6000)
    s1 = Stu('小明',18,iphone)
    s1.iphone.call()

       11.新式类与经典类

        新式类:任何显式或隐式的继承了object的类就称为新式类,在python3中所有的类都是新式类

        经典类: 没有继承object的类,只有在python2中出现

        当出现菱形继承是. 都是先深度,当遇到相同父类时就广度 ,可使用类中__mro__方法查看查找顺序

    class Init(object):
    
        def __init__(self, v):
            print("init")
            self.val = v
    
    class Add2(Init):
    
        def __init__(self, val):
            print("Add2")
            super(Add2, self).__init__(val)
            print(self.val)
            self.val += 2
    
    class Mult(Init):
    
        def __init__(self, val):
            print("Mult")
            super(Mult,self).__init__(val)
            self.val *= 5
    
    class HaHa(Init):
    
        def __init__(self, val):
            print("哈哈")
            super(HaHa, self).__init__(val)
            self.val /= 5
    class Pro(Add2,Mult,HaHa):
        pass
    class Incr(Pro):
    
        def __init__(self, val):
            super(Incr, self).__init__(val)
            self.val+= 1
    # Incr Pro Add2 Mult HaHa Init
    p = Incr(5)
    print(p.val)  # Add2 Mult 哈哈 init 5.0 8.0
    c = Add2(2)
    print(c.val)  #   Add2  init 2  4
    print()
    print(Incr.__mro__)  # (<class '__main__.Incr'>, <class '__main__.Pro'>, <class '__main__.Add2'>, <class '__main__.Mult'>, <class '__main__.HaHa'>, <class '__main__.Init'>, <class 'object'>)

      13:习题:

    # 程序员,拥有,姓名,性别,年龄,工资,和编程技能
    # 项目经理必须有程序员晋升而来,拥有奖金,和管理技能
    # 请使用面向对象来表达这种关系
    # 选做需求,让程序员和项目经理都能调用save将对象序列化到文件
    import pickle
    import os
    
    
    class BaseClass:  # 我们希望可以将存取操作抽取出来.以降低程序的耦合度
    
        def save(self):
            # 先判断系统是否由想要存放的文件夹
            if not os.path.exists(self.__class__.__name__):
                # 如果没有此文件则创建
                os.makedirs(self.__class__.__name__)
            path = os.path.join(self.__class__.__name__, self.name)
            with open(path, 'wb') as f:
                pickle.dump(self, f)
                f.flush()
    
        @classmethod
        def select(cls, name):
            path = os.path.join(cls.__name__, name)
            if os.path.exists(path):
                with open(path, 'rb', ) as f:
                    return pickle.load(f)
    
    
    class Coder(BaseClass):
        def __init__(self, name, gender, age, balance):
            self.name = name
            self.gender = gender
            self.age = age
            self.balance = balance
    
        def program(self):
            print(f"我是{self.name},我会编程")
    
    
    class Pm(Coder, BaseClass):
    
        def __init__(self, name, gender, age, balance, prize):
            super().__init__(name, gender, age, balance)
            self.prize = prize
    
        def menage(self):
            print(f"我会管理")
    
    
    p = Pm('小明', '', 18, 18000, 6000)
    p.save()
    code1 = Pm.select('小明')
    print(type(code1))
    code1.menage() 

    2.封装

      1. 封装 : 封装就是将复杂丑陋的隐私的细节隐藏到内部,也就是隐藏内部的实现细节,并提供给外部访问的接口

      2. 封装的目的:    1. 为了保证关键数据的安全性   2.对外部隐藏实现细节,隔离复杂度

      3. 封装的使用环境    1. 当一些数据不希望被外界直接修改时  2. 当有一些函数或属性不希望被外界使用的时候

      4. 使用方法:  私用化:  在属性或方法前加双下划线   特点: 外界不能直接访问   内部依然可以使用

    class A:
        def __init__(self,name, age):
            self.name = name
            self.__age = age  # 私有属性
    
        def __say(self):  # 私有化方法
            print("from __say")
    
    
        def test(self):    # 在自身内可以直接访问私有属性与私有方法
            print(self.__age,)
            self.__say()
    
        def say(self):
            print('from say')
    
    
    class B(A):
        pass
    
    a = B('小明',18)
    
    print(a.name)   # 小明
    print(a.age)  # 报错.'B' object has no attribute 'age'
    a.__say()  # 报错  'B' object has no attribute '__say'
    a.say()   # from say
    a.test()   # 18  from __say

      5. 在外界访问私有的内容,属性与函数虽然被封装了,,但是有时候我们还是需要在外界访问.这时候我们就可以通过定义方法来完成对私有属性的修改与访问

    class Person:
        def __init__(self, name, age, id_card):
            self.name = name
            self.age = age
            self.__id_card = id_card
    
    
        def get_id_card(self):
            return self.__id_card
    
    
        def alter_id_card(self, new_id_card):
            if len(new_id_card) == 18 or len(new_id_card) == 15:
                print("修改成功")
                self.__id_card = new_id_card
            else:
                print("错误")
    
    
    f = Person('a', 14, '11111111111')
    f.id_card = 2222222  # 在外界临时修改,重新定义,内部并没有修改
    print(f.id_card)  # 2222222
    
    print(f.get_id_card())  # 在外部通过方法获取内置的私有方法
    f.alter_id_card('222222222222222')  # 在外部定义方法来修改私有属性
    print(f.id_card)    # 2222222
    print(f.get_id_card())  # 222222222222222  内部修改成功

      6.在通过方法来修改或访问属性,本身并没有是什么问题,但是这给对象的使用者带来了麻烦,使用者必须要知道那些是普通属性,哪些是私有属性,并且使用不同的方式法来调用他们  ,然后python 就给我们提供了3个有关的装饰器

    @property    获取属性方法
    2  @key,setter  修改属性方法
    3  @key.deleter 删除属性方法
    @property可以将私有属性伪装成普通属性,与普通属性的访问方法一致
    key是被property装饰的方法名称,也就是属性的名称,内部会创建一个对象,变量名称就是函数名称
    所以再是由setter与deleter时必须保证使用对象的名称去调用方法所以时key.setter
    class Person:
        def __init__(self,name,age ,id_card):
            self.name = name
            self.age = age
            self.__id_card = id_card
    
    
        @property
        def id_card(self):
            return self.__id_card
    
        @id_card.setter
        def id_card(self, new_id_card):
            if len(new_id_card) == 18 or len(new_id_card) == 15:
                print("修改成功")
                self.__id_card = new_id_card
            else:
                print("错误")
    
    
        @id_card.deleter
        def id_card(self):
            print('不能删')
    
    
    f = Person('a',14,'11111111111')
    
    print(f.id_card)  # 11111111111
    f.id_card = "222222222222222"
    print(f.id_card)  # 222222222222222
    del f.id_card  # 不能删

      7.封装的原理: 就是再加载类的时候,把__方法或属性 替换成了_类名__方法或属性....  封装的实现原理本质就时替换了变量名称

      8.property 可以用来实现计算属性     计算属性的值不能直接获得,必须通过计算才能获得

    # kg/m**2
    
    class Person:
    
        def __init__(self,height,weight):
            self.height = height
            self.weight = weight
    
        @property
        def bmi(self):
            return self.weight/pow(self.height,2)
    
    
    jay = Person(170,60)
    print(jay.bmi)   # 0.0020761245674740486

      9.接口类:接口就是一组功能的集合,但是接口中仅包含功能的名字,不包含具体的实现代码.接口本质就时一套协议标准,遵循的对象就能被调用,接口的目的就时为了提高扩展性

    class USB:
        def open(self):
            pass
    
        def close(self):
            pass
    
        def  read(self):
            pass
    
        def write(self):
            pass
    
    class Mouse(USB):
        def open(self):
            print("鼠标开机.....")
    
        def close(self):
            print("鼠标关机了...")
    
        def read(self):
            print("获取了光标位置....")
    
        def write(self):
            print("鼠标不支持写入....")
    
    
    def pc(usb_device):
        usb_device.open()
        usb_device.read()
        usb_device.write()
        usb_device.close()
    
    m = Mouse()
    # 将鼠标传给电脑
    pc(m)
    
    class KeyBoard(USB):
        def open(self):
            print("键盘开机.....")
    
        def close(self):
            print("键盘关机了...")
    
        def read(self):
            print("获取了按键字符....")
    
        def write(self):
            print("可以写入灯光颜色....")
    
    # 来了一个键盘对象
    k = KeyBoard()
    pc(k)

      10 抽象类 指的就是包含抽象方法,没有具体函数体方法的类.可以限制子类必须类中定义的抽象方法  导入abc模块

    import abc
    class A(metaclass=abc.ABCMeta):
        @abc.abstractmethod
        def open(self):
            pass
        @abc.abstractmethod
        def close(self):
            pass
        @abc.abstractmethod
        def  read(self):
            pass
        @abc.abstractmethod
        def write(self):
            pass
    
    class Mouse(A):
        def open(self):
            print("鼠标开机.....")
    
        def close(self):
            print("鼠标关机了...")
    
        def read(self):
            print("获取了光标位置....")
    
        def write(self):
            print("鼠标不支持写入....")
    
    
    def pc(usb_device):
        usb_device.open()
        usb_device.read()
        usb_device.write()
        usb_device.close()
    
    m = Mouse()
    # 将鼠标传给电脑
    pc(m)
    
    class KeyBoard(A):
        def open(self):
            print("键盘开机.....")
    
        def close(self):
            print("键盘关机了...")
    
        def read(self):
            print("获取了按键字符....")
    
        def write(self):
            print("可以写入灯光颜色....")
    
    # 来了一个键盘对象
    k = KeyBoard()
    pc(k)

        总结:接口类就是一套协议规范,明确子类们应该具备哪些方法功能

           抽象类就是导入abc模块,强制要求子类必须按照协议中规定来实现

         然后,python不推崇限制语法,所以我们可以设计成为鸭子类型,就是让多个不同类对象具备相同的属性和方法

  • 相关阅读:
    IE浏览器中js使用中文标识符的bug
    Javascript变量作用域
    利用JS的动态语言特性对数组排序
    Javascript动态方法调用与参数修改的问题
    数组的平衡点
    Javascript中各种trim的实现
    js對象的比較
    返回两个数组中非相同的元素
    Javascript中匿名函数的多种调用方式
    SQL Server PreLogin Handshake Acknowledgement Error [duplicate]
  • 原文地址:https://www.cnblogs.com/yanglingyao/p/11251748.html
Copyright © 2020-2023  润新知