zoukankan      html  css  js  c++  java
  • DAY19 面向对象三大特性之多态、封装

    面向对象三大特性之:多态

      多态:指的是一类事物有多种形态。

      例如:动物具有多种形态。

    import abc
    class Animal(metaclass=abc.ABCMeta):  #同一类事物:动物
        @abc.abstractmethod
        def talk(self):
            pass
    
    class People(Animal):   #动物的形态之一:人
        def talk(self):
            print('say hello')
    
    class Dog(Animal):      #动物的形态之一:狗
        def talk(self):
            print('barking')
    
    class Cat(Animal):    #动物的形态之一:猫
        def talk(self):
            print('miao')
    

    多态性

      什么是多态动态绑定?(在继承的背景下使用,也称为多态性。)

      在面向对象方法中一般这样表述多态性:

      -----> 向不同的对象发送同一条消息,不同的对象在接受时会产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数。不同的行为就是指不同的实现,即执行不同的函数。

      -----> 换句人话说,就是在子类和父类中有同名的方法,接受相同的方法调用,都执行自己的同名方法,表现出不一样的行为。

    import abc
    class Animal(metaclass=abc.ABCMeta):  #同一类事物:动物
        @abc.abstractmethod
        def talk(self):
            pass
    
    class People(Animal):   #动物的形态之一:人
        def talk(self):
            print('say hello')
    
    class Dog(Animal):      #动物的形态之一:狗
        def talk(self):
            print('barking')
    
    class Cat(Animal):    #动物的形态之一:猫
        def talk(self):
            print('miao')
    
    p = People()
    d = Dog()
    c = Cat()
    
    p.talk()
    d.talk()
    c.talk()
    >>>
    say hello
    barking
    miao

    鸭子类型(duck Typing)

      在程序设计中,鸭子类型是一种动态类型的一种风格。python崇尚鸭子类型,即“如果看起来像,叫声像而且走路像鸭子的,那么它就是鸭子。”

      例子一:在java语言中,定义一个函数,传递参数的类型必须得到控制,需要定义一个类来定义这些参数的数据类型,参数必须都继承这个类。换成python类型,例如:内置函数len()中的参数,可以是字符串,容器类型,iterator类型。因为这些数据类型的类中都有一个__len__()方法,并没有像java一样定义一个类用来继承,而是通过模糊的概念,并不是通过明确的继承来实现多态,认为拥有__len__()方法的就可以当做参数,符合鸭子类型。

    面向对象三大特性之:封装

       封装:隐藏对象的属性以及实现方法,仅对外提供公共的访问方法。

      封装的优点:

        (1)将变化隔离

        (2)便于使用

        (3)提高安全性

      封装的原则:

        (1)将不需要对外提供的内容隐藏起来。

        (2)把属性都隐藏起来,提供一个公共访问的接口来对其进行访问。

    广义的封装和狭义的封装

      (1)广义的封装:是为了只有这个类的对象才能够使用定义在类中的方法。

    class 类名:
        def func1(self):pass
        def func2(self):pass
        def func3(self):pass
    

      (2)狭义的封装:把一个名字藏在类中

      ##### 私有静态变量/私有对象属性/私有方法 #####

      在python中用双下划线__开头的方式将属性隐藏起来(设置成私有的)

      为什么要定义一个私有变量?

      (1)不想让你看到这个值。

      (2)不想让你修改这个值。

      (3)想让你在修改这个值得时候有一些限制。

      (4)有些属性或者方法不希望被子类继承。

      ##### 私有静态变量/私有对象属性/私有方法 #####

    私有变量

      一般来说类中的属性就应该是共享的,但是语法上可以把类的属性设置成私有的。

    #其实类中的__私有属性,都只是一个变形,变形为“_类名__属性”
    
    #一。设置私有属性
    class A:
        __N = 0 #类的数据属性就应该是共享的,但是语法上是可以把类的属性设置成私有的。
    
    print(A._N)  #在类的外部就不能引用私有的静态变量
    >>>
    AttributeError: type object 'A' has no attribute '_N'
    
    
    #二。但是谨记,都只是变形。
    print(A.__dict__)
    >>>
    {'__module__': '__main__', '_A__N': 0, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
    
    #通过__dict__方法,可以巧妙地打破类的外部不能访问私有属性,但是这种方法被约定俗成的禁止了。
    print(A.__dict__['_A__N'])
    >>>
    0
    
    #其实这仅仅这是一种变形操作
    #类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式:
    
    class A:
        __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
        def __init__(self):
            self.__X=10 #变形为self._A__X
        def __foo(self): #变形为_A__foo
            print('from A')
        def bar(self):
            self.__foo() #只有在类内部才可以通过__foo的形式访问到.
    
    

      总结:

      (1)类中定义的私有变量只能在类的内部使用,如:self.__x,其实已经变形为_类名__x

      (2)这种变形其实是针对外部的变形,令外部无法通过self.__x的方式访问到私有方法。

      (3)在子类中定义__x是无法覆盖父类中的__x属性的,因为在子类中定义就会变形为"_子类__x",在父类中"_父类__x"。

    私有方法

      在继承中,父类如果不想让子类覆盖自己的方法,可以把方法设置成私有方法。

    #正常情况
    >>> class A:
    ...     def fa(self):
    ...         print('from A')
    ...     def test(self):
    ...         self.fa()           #看self代表谁
    ... 
    >>> class B(A):
    ...     def fa(self):
    ...         print('from B')
    ... 
    >>> b=B()
    >>> b.test()
    from B
     
    
    #把fa定义成私有的,即__fa
    >>> class A:
    ...     def __fa(self):     #在定义时就变形为_A__fa
    ...         print('from A')
    ...     def test(self):
    ...         self.__fa()     #只会与自己所在的类为准,即调用_A__fa
    ... 
    >>> class B(A):
    ...     def __fa(self):
    ...         print('from B')
    ... 
    >>> b=B()
    >>> b.test()
    from A

    内置函数补充之:property

      property是一个装饰器,它的作用是将一个方法伪装成一个属性。

    class Student:
        def __init__(self,name,age):
            self.__name = name
            self.age = age
    
        @property     #将一个方法伪装成一个属性
        def name(self):
            return self.__name
    
    zhuge = Student('诸葛',20)
    print(zhuge.name)
    >>>
    诸葛
    

      为什么要用property?

       将一个类的函数定义成一个属性后,对象在去使用obj.name的时候,根本不会想到这个是经过函数运算后返回的,遵循了统一访问的原则。

    ps:面向对象中封装的三大方式:

     【public】:这种就是对外公开,不封装。

     【protected】:这种封装方式就是对外不公开,但是对子类公开。

      【private】:这种封装方式就对谁的不公开

    在python中并没有在语法上把它们三种都内建到class机制中,在c++里面一般会把所有的数据都设置成私有的,然后提供set和get方法去修改和获取,在python中可以通过property去实现。

    class Foo:
        def __init__(self,val):
            self.__NAME= val    #将所有数据属性都转化为私有属性存起来。
    
        @property
        def name(self):
            return self.__NAME
    
        @name.setter
        def name(self,value):
            if not isinstance(value,str):
                raise TypeError('%s must be str'%value)
            self.__NAME = value  # 通过类型检测后,将值value存放到真实的位置self.__NAME
    
        @name.deleter
        def name(self):
            raise TypeError('can not delete')
    
    f = Foo('egon')
    # print(f.name)   #通过name函数返回self.__NAME
    
    # f.name = 10      #TypeError: 10 must be str
    del f.name         #TypeError: can not delete
    

      property总结:

     (1)一个静态属性property本质就是实现了get,set,delete三种方法。

     (2)只有在属性xxx定义了property后,才能使用xxx.setter,xxx.deleter。

  • 相关阅读:
    AtCoder Beginner Contest 205
    Codeforces Round #725 (Div. 3)
    Educational Codeforces Round 110 (Rated for Div. 2)【A
    Codeforces Round #722 (Div. 2)
    AtCoder Beginner Contest 203(Sponsored by Panasonic)
    AISing Programming Contest 2021(AtCoder Beginner Contest 202)
    PTA 520 钻石争霸赛 2021
    Educational Codeforces Round 109 (Rated for Div. 2)【ABCD】
    AtCoder Beginner Contest 200 E
    Educational Codeforces Round 108 (Rated for Div. 2)【ABCD】
  • 原文地址:https://www.cnblogs.com/hebbhao/p/9555340.html
Copyright © 2011-2022 走看看