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 静态方法 没有默认的参数 就象函数一样









  • 相关阅读:
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之六 多点触控
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之九 定位
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之七 重力感应
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之五 保存数据的几种方式
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之八 照相机
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之三 Application 配置详解
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之四 打开与关闭应用程序是的保存数据
    ADOBE FLASH BUILDER 4.6 IOS 开发之部署与调试
    [译] 高性能JavaScript 1至5章总结
    页签及盒子的web标准实现
  • 原文地址:https://www.cnblogs.com/olivia2018/p/8313083.html
Copyright © 2011-2022 走看看