zoukankan      html  css  js  c++  java
  • 面向对象之多态

    一.封装方法

    语法:方法名前加双下划线

    优点:1.提高安全性;2.隔离复杂度(将复杂的内容隔离到内部,使用者通过简单的使用接口就可进行访问)

    # ATM 的取款功能
    # 1.插入银行卡 2.输入密码 3.选择取款金额  4.取款
    
    class ATM:
        def __insert_card(self):
            print("插入银行卡...")
    
        def __input_pwd(self):
            print("输入密码...")
        def __select_money(self):
            print("选择取款金额...")
        def withdraw(self):
            self.__insert_card()
            self.__input_pwd()
            self.__select_money()
            print("取款成功!....")
    
    atm = ATM()
    
    atm.withdraw() # 外部调用这个简单的接口 就能完成一系列复杂的操作
    
    # atm.select_money()  #直接调用内部的方法 是没有意义的无法完成整个功能
    
    # 当然用户按照流程一一调用也可以完成功能 但是太麻烦
    # atm.insert_card()
    # atm.input_pwd()
    # atm.select_money()
    封装方法

    二.封装的实现原理

    python是通过语法的转换来实现封装的,具体就是在私有的属性和方法名前,自动加上了_类名,因此__属性名和__方法名就转换成了_类名__方法名和_类名__属性名。

    注:

    1.只有在类的内部的双下划线开头的属性和方法才会被自动转换,且这种转换过程只执行一次,在类定义完成之后,后续在外部添加的双下划线开头的属性和方法是不会进行转换的。

    2.父类中被封装的方法,子类中无法进行访问和覆盖。

    3.我们知道了封装的实现原理,也可以绕过封装的限制进行访问,但是这种做法是毫无意义的。

    class Person:
    
        def __init__(self,name,sex,age,idCard):
            self.name = name
            self.sex = sex
            self.__age = age
            self.__idCard = idCard
    
        def get_idCard(self):
            return self.__idCard
    
        def __test(self):
            pass
    
        print("aaaaaaaaaa")
    
    
    # p = Person("比尔盖茨","男",20,"322323232332332")
    #
    # # print(p.__idCard)
    # p.__idCard = "XXXXXX"
    # print(p.__idCard)
    #
    # print(p.get_idCard())
    #
    # print(p.__dict__)
    # print(Person.__dict__)
    #
    #
    # p.__xxxxxxxxxxxx = 1
    #
    # print(p.__dict__)
    
    
    # 通过__dict__ 可以发现
    # 1.私有的属性和方法名称 前自动加上了_类名 python就是通过这样的转换方式来实现封装
    # 2.只有在类的内部的双下划线才会被自动转换,并且这个转换过程只执行一次,在类定义完成后 后续添加的双下划线开头的名称是不会自动转换的
    # 3.父类中私有的方法 子类中无法使用
    
    
    #在父类中定义的私有方法 能不能被子类所覆盖?
    
    
    # class A:
    #     def __f1(self):
    #         print("A __f1")
    #
    # class B(A):
    #     def __f2(self):
    #         # self.__f1()
    #         super().__f1()
    #         print("B __f2")
    #
    #     def test(self):
    #         self.__f2()
    #
    # b = B()
    # b.test()
    
    
    
    
    # 子类无法覆盖父类的私有方法
    
    # class  A:
    #     def f(self):
    #         self.__f1()   #_A__f1
    #
    #     def __f1(self):
    #         print("A  __f1")
    #
    # class B(A):
    #     def __f1(self):  # _B__f1
    #         print("B __f1")
    #
    #     def f2(self):
    #         self.f()
    #
    # b = B()
    # b.f2()
    
    # 之所以无法覆盖 是因为 子类和父类中的私有方法 名称必然不相同 所以无法覆盖   子类的方法一定子类独有的 因为名称不同
    
    
    
    
    class A:
        __age = 10
    
    # 绕过封装的限制直接访问  这是毫无意义的
    print(A._A__age)
    封装的实现原理

    三.property装饰器

    1.什么是property?

    property是一种特殊的属性,访问它时会执行一段功能(函数),然后返回值。

    2.为什么用property?

    当一些属性的值,不是固定的,而是通过计算得来的,我们就需要为其添加方法才能完成计算。这样一来该属性的使用就会变成调用方法才能使用它,会给使用者造成困惑。这时候就需要用到property装饰器装饰该方法,使其伪装成一个属性。在使用者调用该方法时,会跟访问属性的形式一样,从而形成了访问属性的统一标准。

    3.如何用property?

    在需要装饰的方法上方,加上@property即可。另外property还提供了setter(用于修改属性的值),deleter(用于删除属性的值)。

    # BIM案例:
    class Person:
        def __init__(self,name,weight,height):
            self.name = name
            self.weight = weight
            self.height = height
            # self.bmi = weight/(height*height)
        # def bmi(self):
        #     return self.weight / (self.height * self.height)
        @property
        def bmi(self):
            return self.weight / (self.height * self.height)
    
    p = Person("尔晴",50,1.5)
    # print(p.bmi)
    # p.weight = 90
    # print(p.bmi)
    
    # 现在 虽然可以实现需求 但是我们把一个属性变成了一个行为 这是不合理的
    # print(p.bmi())
    # p.weight = 90
    # print(p.bmi())
    
    # 使用property装饰器 可以将一个方法伪装成一个属性
    print(p.bmi)
    p.height += 0.2
    print(p.bmi)
    
    
    class Student:
        def __init__(self,name,sex,idCard):
            self.name = name
            self.sex = sex
            self.__idCard = idCard
    
        def get_idCard(self):
            return self.__idCard
    
        def set_idCard(self,new_id):
            self.__idCard = new_id
    
        @property # 需要掌握
        def idCard(self):
            return self.__idCard
    
    
        @idCard.setter #了解的
        def idCard(self,new_id):
            self.__idCard = new_id
    
        @idCard.deleter # 了解的
        def idCard(self):
            print("身份证属性被删除了.....")
            del self.__idCard
    
    
    stu = Student("尔康","","323254554554")
    
    # print(stu.get_idCard())
    
    # stu.set_idCard("xxxx")
    
    print(stu.get_idCard()) # 使用装饰器前
    print(stu.name) # 普通属性的访问
    
    print(stu.idCard) # 使用装饰器后
    
    stu.idCard = "aaaaaaa" # 使用装饰器后的修改操作
    
    print(stu.idCard)
    
    del stu.idCard
    property的使用

    四.多态

    1.什么是多态?

    多态简单的来说就是一个事物有多种状态。在程序中,不同对象可以享有同一方法,并作出不同的行为,产生不同的结果。

    2.为什么用多态?

      1.增加了程序的灵活性

    以不变应万变,不论对象千变万化,使用者都用同一种方式去调用。

      2.增加了程序的可扩展性

    通过继承基类创建一个新的类,使用者无需修改代码,还是使用之前的方式去调用。

    3.如何实现多态?

    让几个不同的类继承相同的父类,这样子类就可以拥有相同的方法,每个子类都要覆盖父类的方法,这样子类的对象行为都不同。

    class Animal:
        def eat(self):
            print("动物在吃东西...")
        def sleep(self):
            print("动物在睡觉...")
        def drink(self):
            print("动物需要水.....")
    
    
    class Person(Animal):
        def eat(self):
            print("人吃粮食...")
    
    class Pig(Animal):
        def eat(self):
            print("猪吃饲料...")
    
    class Dog(Animal):
        def eat(self):
            print("狗吃骨头...")
    
    
    person = Person()
    pig = Pig()
    dog = Dog()
    
    person.eat()
    pig.eat()
    dog.eat()
    
    #假设你学习了C1驾照  意味着 所有C1类的汽车都能开  因为每种C1汽车的驾驶方式相同
    
    
    # 当使用了多态之后 对象的使用者不需要关系这个对象具体的实现,只需要知道该对象属于哪个基类,就能直接使用它
    # 如此扩展性变高了
    
    
    class Phone:
        def call(self):
            print("手机就能打电话..")
    
        def send_msg(self):
            print("手机能发短信..")
    
    
    class WindowsPhone(Phone):
        def call(self):
            print("拨号打电话..")
    
        def send_msg(self):
            print("输入号码发短信..")
    
    class IPhone(Phone):
        def call(self):
            print("拨号打电话..")
    
    
        def send_msg(self):
            print("输入号码发短信..")
    
    
    
    
    # 可以定义一个方法接收一个手机为参数 无论是是类型的手机 都可以被使用
    
    def CALL(phone):
        phone.call()
    
    wp = WindowsPhone()
    ipx = IPhone()
    
    CALL(wp)
    CALL(ipx)
    
    
    # 系统内置的方法有很多都体现了多态
    
    
    print(len("abc"))
    print(len([1,2,3,4,]))
    print(len({"name":"123","sex":"man"}))
    
    print("abc".__len__())
    print([1,2,3,4,].__len__())
    print({"name":"123","sex":"man"}.__len__())
    
    print(len({1,23,4,5}))
    多态的实现

    4.多态之ABC模块

    abc模块(abstract  class(抽象类)),使用abc模块来限制子类的步骤。

    4.1.为类中指定元类为abc.ABCMeta

    4.2.在相应的方法加上abc.abstractmethod装饰器

    import abc
    # abstract class 是抽象类的缩写   抽象的意思是 不清晰 不具体 看不懂
    
    #使用ABC模块来限制子类 的步骤
    #1.为类中指定元类为abc.ABCMeta
    #2.在相应的方法上加上abc.abstractmethod装饰器
    
    class Animal(metaclass=abc.ABCMeta):
    
        @abc.abstractmethod
        def eat(self):
            pass
    
        @abc.abstractmethod
        def drink(self):
            pass
    
    
    class Cat(Animal):
        def eat(self):
            print("猫爱吃鱼肉...")
    
        def drink(self):
            print("用舌头舔..")
    
    class Dog(Animal):
        def eat(self):
            print("狗爱吃骨头...")
        def drink(self):
            print("用舌头舔..")
    
    class Pig(Animal):
        def eat(self):
            print("猪 爱吃草...")
    
        def drink(self):
            print("用嘴吸的..")
    
    p = Pig()
    # p.eat()
    
    c = Cat()
    # c.eat()
    
    # 多态的好处 完全不需要考虑得到的对象时声明类型 只要知道了其基类中的内容就能使用
    def feeding(animal):
        animal.eat()
        animal.drink()
    
    feeding(c)
    feeding(p)
    # 多态中的基类 相当于(协议 标准 规范) 要求子类必须满足这些标准
    ABC模块的使用
    import abc
    
    # 电脑基类
    class Computer(metaclass=abc.ABCMeta):
    
        @abc.abstractmethod
        def open(self):
            pass
    
        @abc.abstractmethod
        def shutdown(self):
            pass
    
    
    #
    class DesktopComputer(Computer):
        def open(self):
            print("台式机正在启动....")
    
        def shutdown(self):
            print("台式机正在关机....")
    
    
    class Worker:
    
        def working(self,pc):
            # 先开机
            pc.open()
            print("工作中.....")
            pc.shutdown()
    
    
    w1 = Worker()
    
    dp = DesktopComputer()
    
    w1.working(dp)
    
    
    # 增加了笔记本电脑
    class BookComputer(Computer):
    
        def open(self):
            print("笔记本正在启动....")
    
    
        def shutdown(self):
            print("笔记本正在关机....")
    
    bc = BookComputer()
    w1.working(bc)
    
    class PadComputer(Computer):
    
        def open(self):
            print("平板正在启动....")
    
    
        def shutdown(self):
            print("平板正在关机....")
    
    bc = PadComputer()
    w1.working(bc)
    多态的练习

    五.鸭子类型

    python推崇的是鸭子类型,推崇简单的编程方式。鸭子类型指的是如果一个对象叫声像鸭子,走路的姿势也像鸭子,那就把它当成鸭子。对应到代码中:只要你的行为一样,就把你当成同一个类型来对待。

    class Duck:
    
        def bark(self):
            print("鸭子嘎嘎叫...")
    
        def run(self):
            print("摇摇晃晃走....")
    
    class Chicken:
        def bark(self):
            print("鸡咯咯叫...")
    
        def run(self):
            print("摇摇晃晃走....")
    
    def test(obj):
        obj.bark()
        obj.run()
    duck = Duck()
    c = Chicken()
    
    test(duck)
    test(c)
    
    # 如果你足够自觉 你可以不使用abc模块 也不需要基类 自觉地将方法名字都写成一样 同样可以实现多态
    # 这种方式称之为鸭子类型
    鸭子类型

     其实我们一直在享受着多态性带来的好处,比如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__()
    
    len(s)
    len(l)
    len(t)
    View Code
  • 相关阅读:
    UVA 11488 Hyper Prefix Sets (字典树)
    UVALive 3295 Counting Triangles
    POJ 2752 Seek the Name, Seek the Fame (KMP)
    UVA 11584 Partitioning by Palindromes (字符串区间dp)
    UVA 11100 The Trip, 2007 (贪心)
    JXNU暑期选拔赛
    计蒜客---N的-2进制表示
    计蒜客---线段的总长
    计蒜客---最大质因数
    JustOj 2009: P1016 (dp)
  • 原文地址:https://www.cnblogs.com/wangke0917/p/10137354.html
Copyright © 2011-2022 走看看