zoukankan      html  css  js  c++  java
  • python 面向对象的三大特性

    继承

    继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类。

    class A():pass   # 父类,基类,超类
    class B:pass   # 父类,基类,超类
    class C(A,B):pass # 子类,派生类
    class D(A):pass # 子类,派生类

    # 一个类 可以被多个类继承
    # 一个类 可以继承多个父类——python里

    __bases__查看所有继承的父类
    __bases__则是查看所有继承的父类
    print(A.__bases__)
    (<class 'object'>,)
    print(C.__bases__)
    (<class '__main__.A'>, <class '__main__.B'>)

     python3 只存在新式类

    没有继承父类时默认继承object,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。

    继承与抽象(先抽象再继承)
    抽象即抽取类似或者说比较像的部分。

    抽象分成两个层次:

    1.将奥巴马和梅西这俩对象比较像的部分抽取成类;

    2.将人,猪,狗这三个类比较像的部分抽取成父类。

    抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度)

    继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。

    (子类 是 父类)

    抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类。

    函数名的重用

    class Animal:
        def __init__(self,name,aggr,hp):
            self.name = name
            self.aggr = aggr
            self.hp = hp
            self.func()
        def func(self):
            print(123)
    #
    class Dog(Animal):
        def func(self):
            print(456)
        def bite(self,person):
            person.hp -= self.aggr
    d = Dog()
    #--> 456
    只要是子类的对象调用,子类中有的名字 一定用子类的

     在子类中,新建的重名的函数属性,在编辑函数内功能的时候,有可能需要重用父类中重名的那个函数功能,应该是用调用普通函数的方式,

    即:类名.func(),此时就与调用普通函数无异了,因此即便是self参数也要为其传值.

    class Animal:
        def __init__(self,name,aggr,hp):
            self.name = name
            self.aggr = aggr
            self.hp = hp
    
        def eat(self):
            print('吃药回血')
            self.hp+=100
    
    class Dog(Animal):
        def __init__(self,name,aggr,hp,kind):
            Animal.__init__(self,name,aggr,hp)  #
            self.kind = kind       # 派生属性
        

      def eat(self): Animal.eat(self) # 如果既想实现新的功能也想使用父类原本的功能,还需要在子类中再调用父类 self.teeth = 2

      def bite(self,person): # 派生方法 person.hp -= self.aggr

     在python3中,子类执行父类的方法也可以直接用super方法.(super只在python中存在)

    class Dog(Animal):
        def __init__(self,name,aggr,hp,kind):
            super().__init__(name,aggr,hp)  # 只在新式类中有,python3中所有类都是新式类
            # super(Animal,self).__init__(name,aggr,hp)
            # Animal.eat(self)
            self.kind = kind       # 派生属性
        

      def eat(self):print('dog eating') jin = Dog('金老板',200,500,'teddy') print(jin.name) jin.eat() super(Dog,jin).eat()

    小结

    父类中没有的属性 在子类中出现 叫做派生属性
    父类中没有的方法 在子类中出现 叫做派生方法
    只要是子类的对象调用,子类中有的名字 一定用子类的,子类中没有才找父类的,如果父类也没有报错# 如果父类、子类都有,用子类的。
        # 如果还想用父类的,单独调用父类的:
        #       父类名.方法名 需要自己传self参数
        #       super().方法名 不需要自己传self
     正常的代码中 单继承 === 减少了代码的重复
     继承表达的是一种 子类 是 父类的关系

    多继承

    单继承 : 子类有的用子类 ,子类没有用父类。
    多继承中,我们子类的对象调用一个方法,默认是就近原则,找的顺序是什么?

    class F:
        def func(self): print('F')
    class A(F):pass
        # def func(self): print('A')
    class B(A):
        pass
        # def func(self): print('B')
    class E(F):pass
        # def func(self): print('E')
    class C(E):
        pass
        # def func(self): print('C')
    
    class D(B,C):
        pass
        # def func(self):print('D')
    
    d = D()
    # d.func()

    python2.7 新式类和经典类共存,新式类要继承object
    python3 只有新式类,默认继承object

    经典类中 ,深度优先
    新式类中 ,广度优先

    经典类和新式类还有一个区别 mro方法只在新式类中存在
    super 只在python3中存在
    super的本质 :不是单纯找父类 而是根据调用者的节点位置的广度优先顺序来的

    class A(object):
        def func(self): print('A')
    
    class B(A):
        def func(self):
            super().func()
            print('B')
    
    class C(A):
        def func(self):
            super().func()
            print('C')
    
    class D(B,C):
        def func(self):
            super().func()
            print('D')
    
    b = D()
    b.func()
    print(B.mro())#[<class '__main__.B'>, <class '__main__.A'>, <class 'object'>] 

    钻石问题

    新式类 : 顺序如图所示,以根节点D为依据,在保证每个类里的函数都能取到的基础上,广度优先。

    经典类:深度优先 图1 B->A   图2 dbafce(不再走f,因为之前走过)   图3 dbace 

    小结

    继承 : 什么是什么的关系(子类是父类)
    单继承 *****
        先抽象再继承,几个类之间的相同代码抽象出来,成为父类
        子类自己没有的名字,就可以使用父类的方法和属性
        如果子类自己有,一定是先用自己的
        在类中使用self的时候,一定要看清楚self指向谁
    多继承 ***
        新式类和经典类:
            多继承寻找名字的顺序 : 新式类广度优先,经典类深度优先
            新式类中 有一个类名.mro方法,查看广度优先的继承顺序
            python3中 有一个super方法,根据广度优先的继承顺序查找上一个类

     抽象类和接口类

    java : 面向对象编程
    设计模式 —— 接口
    接口类 : python原生不支持(只是一种思想)
    抽象类 : python原生支持的

    class Wechat(Payment):
        def pay(self,money):
            print('已经用微信支付了%s元'%money)
    
    class Alipay(Payment):
        def pay(self,money):
            print('已经用支付宝支付了%s元' % money)
    
    class Applepay(Payment):
        def pay(self,money):
            print('已经用applepay支付了%s元' % money)
    
    def pay(pay_obj,money):  # 统一支付入口
        pay_obj.pay(money)
    
    w = Wechat()
    ap = Apple()
    # a = Ali() #TypeError: Can't instantiate abstract class Ali with abstract methods pay
    # pay(w,100)  #微信支付了100
    # pay(ap,100) #苹果支付了100
    # pay(a,100)
    p = Payment() #Can't instantiate abstract class Payment with abstract methods pay 不能创建

    接口类的多继承问题

    接口隔离原则
    使用多个专门(Fly_Animal、Walk_Animal等)的接口,而不使用单一(Animal)的总接口。即客户端不应该依赖那些不需要的接口。

    from abc import abstractmethod,ABCMeta
    class Swim_Animal(metaclass=ABCMeta):
        @abstractmethod
        def swim(self):pass
    
    class Walk_Animal(metaclass=ABCMeta):
        @abstractmethod
        def walk(self):pass
    
    class Fly_Animal(metaclass=ABCMeta):
        @abstractmethod
        def fly(self):pass
    
    class Tiger(Walk_Animal,Swim_Animal):
        def walk(self):
            pass
        def swim(self):
            pass
    class OldYing(Fly_Animal,Walk_Animal):pass
    class Swan(Swim_Animal,Walk_Animal,Fly_Animal):pass
    View Code
    抽象类 : 
    规范
    一般情况下 单继承 能实现的功能都是一样的,所以在父类中可以有一些简单的基础实现
    多继承的情况 由于功能比较复杂,所以不容易抽象出相同的功能的具体实现写在父类中


    抽象类还是接口类 : 面向对象的开发规范 所有的接口类和抽象类都不能实例化
    java :
    java里的所有类的继承都是单继承,所以抽象类完美的解决了单继承需求中的规范问题
    但对于多继承的需求,由于java本身语法的不支持,所以创建了接口Interface这个概念来解决多继承的规范问题

    python
    python中没有接口类 :
    python中自带多继承 所以我们直接用class来实现了接口类
    python中支持抽象类 : 一般情况下 单继承 不能实例化
    且可以实现python代码
    #一切皆文件
    import abc #利用abc模块实现抽象类
    class All_file(metaclass=abc.ABCMeta):
        all_type='file'
        @abc.abstractmethod #定义抽象方法,无需实现功能
        def read(self):
            '子类必须定义读功能'
            with open('filaname') as f:
                pass
    
        @abc.abstractmethod #定义抽象方法,无需实现功能
        def write(self):
            '子类必须定义写功能'
            pass
    
    class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
        def read(self):
            print('文本数据的读取方法')
        def write(self):
            print('文本数据的读取方法')
    
    class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法
        def read(self):
            print('硬盘数据的读取方法')
    
        def write(self):
            print('硬盘数据的读取方法')
    
    class Process(All_file): #子类继承抽象类,但是必须定义read和write方法
        def read(self):
            print('进程数据的读取方法')
    
        def write(self):
            print('进程数据的读取方法')
    
    wenbenwenjian=Txt()
    
    yingpanwenjian=Sata()
    
    jinchengwenjian=Process()
    
    #这样大家都是被归一化了,也就是一切皆文件的思想
    wenbenwenjian.read()
    yingpanwenjian.write()
    jinchengwenjian.read()
    
    print(wenbenwenjian.all_type)
    print(yingpanwenjian.all_type)
    print(jinchengwenjian.all_type)
    View Code
    什么是多态
    多态 python 天生支持多态,python 动态强类型的语言
    鸭子类型
    不崇尚根据继承所得来的相似
    我只是自己实现我自己的代码就可以了。
    如果两个类刚好相似,并不产生父类的子类的兄弟关系,而是鸭子类型
    list tuple 这种相似,是自己写代码的时候约束的,而不是通过父类约束的
    class List():
        def __len__(self):pass
    class Tuple():
        def __len__(self):pass
    
    def len(obj):
        return obj.__len__()
    
    l = Tuple()
    len(l)
    优点 : 松耦合 每个相似的类之间都没有影响
    缺点 : 太随意了,只能靠自觉
    封装
    广义上面向对象的封装 :代码的保护,面向对象的思想本身就是一种
    只让自己的对象能调用自己类中的方法

    狭义上的封装 —— 面向对象的三大特性之一
    属性 和 方法都藏起来 不让你看见
    class Person:
        __key = 123  # 私有静态属性
        def __init__(self,name,passwd):
            self.name = name
            self.__passwd = passwd   # 私有属性
    
        def __get_pwd(self):         # 私有方法
            return self.__passwd   #只要在类的内部使用私有属性,就会自动的带上_类名
    
        def login(self):          # 正常的方法调用私有的方法
            self.__get_pwd()
    
    alex = Person('alex','alex3714')
    print(alex._Person__passwd)   # _类名__属性名
    print(alex.get_pwd())
    所有的私有 都是在变量的左边加上双下划綫
    对象的私有属性
    类中的私有方法
    类中的静态私有属性
    所有的私有的 都不能在类的外部使用(自觉_person)
    class Room:
        def __init__(self,name,length,width):
            self.__name = name
            self.__length = length
            self.__width = width
        def get_name(self):
            return self.__name
        def set_name(self,newName):
            if type(newName) is str and newName.isdigit() == False:
                self.__name = newName
            else:
                print('不合法的姓名')
        def area(self):
            return self.__length * self.__width
    
    jin = Room('金老板',2,1)
    print(jin.area())
    jin.set_name('2')
    print(jin.get_name())
    
    # 假设父类的私有属性 能被 子类调用么
    class Foo:
        __key = '123'       # _Foo__key
    
    class Son(Foo):
        print(Foo.__key)     # _Son__key 不能
    
    
    # 会用到私有的这个概念de场景
    # 1.隐藏起一个属性 不想让类的外部调用
    # 2.我想保护这个属性,不想让属性随意被改变
    # 3.我想保护这个属性,不被子类继承
    接口类 抽象类
    python中没有接口类,有抽象类,abc模块中的metaclass = ABCMeta,@abstructmethod
    本质是做代码规范用的,希望在子类中实现和父类方法名字完全一样的方法
    在java的角度上看 是有区别的
        java本来就支持单继承 所以就有了抽象类
        java没有多继承 所以为了接口隔离原则,设计了接口这个概念,支持多继承了
    python及支持单继承也支持多继承,所以对于接口类和抽象类的区别就不那么明显了
    甚至在python中没有内置接口类
    
    多态和鸭子类型
    多态 —— python天生支持多态
    鸭子类型 —— 不依赖父类的情况下实现两个相似的类中的同名方法
    
    封装 —— 私有的
    在python中只要__名字
    在python中只要__名字,就把这个名字私有化了
    私有化了之后 就不能能从类的外部直接调用了
    静态属性 方法 对象属性 都可以私有化
    这种私有化只是从代码级别做了变形,并没有真的约束
    变形机制 _类名__名字 在类外用这个调用,在类的内部直接__名字调用
    小结

    property
    内置装饰器函数 只在面向对象中使用

    # 属性 查看 修改 删除
    class Person:
        def __init__(self,name):
            self.__name = name
            self.price = 20
        @property
        def name(self):
            return self.__name
        @name.deleter
        def name(self):
            del self.__name
        @name.setter
        def name(self,new_name):
            self.__name = new_name
    brother2 = Person('二哥')
    # del Person.price
    brother2.name = 'newName'
    brother2
    # del brother2.name
    print(brother2.name)
    method 方法
    staticmathod 静态的方法 ***
    classmethod 类方法 ****
    类的操作行为
    class Goods:
        __discount = 0.8
        def __init__(self,name,price):
            self.name = name
            self.__price = price
        @property
        def price(self):
            return self.__price * Goods.__discount
        @classmethod   # 把一个方法 变成一个类中的方法,这个方法就直接可以被类调用,不需要依托任何对象
        def change_discount(cls,new_discount):  # 修改折扣
            cls.__discount = new_discount
    apple = Goods('苹果',5)
    print(apple.price)
    Goods.change_discount(0.5)   # Goods.change_discount(Goods)
    print(apple.price)
    当这个方法的操作只涉及静态属性的时候 就应该使用classmethod来装饰这个方法
    # 在完全面向对象的程序中,
    # 如果一个函数 既和对象没有关系 也和类没有关系 那么就用staticmethod将这个函数变成一个静态方法
    class Login:
        def __init__(self,name,password):
            self.name = name
            self.pwd = password
        def login(self):pass
    
        @staticmethod
        def get_usr_pwd():   # 静态方法
            usr = input('用户名 :')
            pwd = input('密码 :')
            Login(usr,pwd)
    
    Login.get_usr_pwd()
    类方法和静态方法 都是类调用的。
    对象可以调用类方法和静态方法,一般情况下 推荐用类名调用。
    类方法 有一个默认参数 cls 代表这个类 cls 静态方法 没有默认的参数 就象函数一样









  • 相关阅读:
    0814防盗链访问控制代理
    0811Nginx访问日志设置
    0810Nginx安装
    0809LNMP架构介绍
    PHP安装
    mariaDB安装Apache安装(httpd)
    LAMP构架介绍
    shell基础知识(2)
    shell基础知识(1)
    yum更换国内源、yum下载rpm包、源码包安装
  • 原文地址:https://www.cnblogs.com/olivia2018/p/8313083.html
Copyright © 2011-2022 走看看