• python高级-面向对象特性(12)


    一、继承的概念

    在现实生活中,继承一般指的是子女继承父辈的财产,在程序中,继承描述的是事物之间的所属关系,例如猫和狗都属于动物,程序中便可以描述为猫和狗继承自动物;同理,波斯猫和巴厘猫都继承自猫,而沙皮狗和斑点狗都继承足够,如下如所示:

    二、继承的示例

    class Cat(object):
        def __init__(self,name,color="白色"):
            self.name = name
            self.color = color
    
        def run(self):
            print("%s:在跑"%self.name)
    
    class Bosi(Cat):
        def setNewName(self,newName):
            self.name = newName
    
        def eat(self):
            print("%s:在吃"%self.name)
    
    bs = Bosi("波斯猫")
    print("bs的名字是:%s,颜色是:%s"%(bs.name,bs.color))
    bs.eat()
    bs.setNewName("汤姆猫")
    bs.run()

    运行结果为:

    bs的名字是:波斯猫,颜色是:白色
    波斯猫:在吃
    汤姆猫:在跑

    说明:

    • 虽然子类没有定义__init__()方法,但是父类有。所以在子类集成父类的时候这个方法就被继承了,所以只要创建Bosi的对象,就默认执行了那个继承过来的__init__()方法
    • 子类在继承的时候,在定义类时,小括号()中为父类的名字
    • 父类的所有非私有的属性、方法、会被继承给子类

    注意:

    • 私有的属性,不能通过对象直接访问,但是可以通过方法访问
    • 私有的方法,不能通过对象直接访问
    • 私有的属性、方法,不会被子类继承,也不能被访问
    • 一般情况下,私有的属性、方法都是不对外公布的,往往用来做内部的事情,起到安全的作用
    class Animal(object):
        def __init__(self, name = "动物",color = "白色"):
            self.__name = name
            self.color = color
        
        def __test1(self):
            print(self.__name)
            print(self.color)
    
        def test2(self):
            print(self.__name)
            print(self.color)
    
    class Dog(Animal):
        def dogTest1(self):
            #不能访问父类的私有属性:AttributeError: 'Animal' object has no attribute '__name'
            #print(self.__name)
            print(self.color)
    
        def dogTest2(self):
            #self.__test1()
            self.test2()
    
    A = Animal()
    #print(A.__name)
    print(A.color)
    #不能访问父类的私有方法:AttributeError: 'Animal' object has no attribute '__test1'
    #A.__test1()
    A.test2()
    
    print("-----------------分割线-----------------")
    D = Dog(name="阿黄",color = "黄色")
    D.dogTest1()
    D.dogTest2()

    运行结果为:

    白色
    动物
    白色
    -----------------分割线-----------------
    黄色
    阿黄
    黄色

    三、多继承

    从图中能够看出,所谓多继承,即子类有多个父类,并且具有它们的特征

    Python中多继承的格式如下:

    class A:
        def printA(self):
            print("---A---")
    
    class B:
        def printB(self):
            print("---B---")
    
    #定义一个子类继承A,B
    class C(A,B):
        def printC(self):
            print("---C---")
    
    obj_C = C()
    obj_C.printA()
    obj_C.printB()

    运行结果为:

    ---A---
    ---B---

    说明

    • python中是可以多继承的
    • 父类中的方法、属性,子类会继承
    • 如果多个父类中有同一个方法,谁写在前面就调用谁的方法
    class A:
        def printA(self):
            print("---A---")
    
    class B:
        def printB(self):
            print("---B---")
    
    #定义一个子类继承A,B
    class C(A,B):
        def printC(self):
            print("---C---")
    
    obj_C = C()
    obj_C.printA()
    obj_C.printB()
    #可以查看一个雷的对象搜索方法时的先后顺序
    print(C.__mro__)

    运行结果为:

    ---A---
    ---B---
    (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)

    四、重写父类方法与调用父类方法

    1、重写父类方法

    所谓重写,就是子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法

    class Cat(object):
        def sayHello(self):
            print("Hello:Cat")
    
    class Bosi(Cat):
        def sayHello(self):
            print("Hello:Bosi")
    
    bs = Bosi()
    bs.sayHello()

    运行结果为:Hello:Bosi

    2、调用父类方法

    class Cat(object):
        def __init__(self,name):
            self.name = name
            self.color = "黄色"
    
        
    
    class Bosi(Cat):
        def __init__(self,name):
            #Cat.__init__(self,name) #python2的语法
            #调用父类的方法
            super().__init__(name)
    
            def getName(self):
                return self.name
            pass
    
    bs = Bosi("波斯")
    print(bs.name)
    print(bs.color)

    运行结果为:

    波斯
    黄色

    五、多态

    • 多态的概念是应用于Java和C#这一类强类型语言中
    • 所谓多态:定义时的类型和运行时的类型不一样,此时就成为多态
    class F1(object):
        def show(self):
            print("F1.show")
    
    class S1(F1):
        def show(self):
            print("S1.show")
    
    class S2(object):
        def show(self):
            print("S2.show")
    
    def func(obj):
        obj.show()
    
    s1_obj = S1()
    func(s1_obj)
    
    s2_obj = S2()
    func(s2_obj)

    运行结果为:S1.show、S2.show

    六、类属性、实例属性

    了解类基本的东西之后,下面看一下python中这几个概念的区别、

    在前面的例子中我们接触到的就是实例属性(对象属性),类属性就是类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在一个副本,这个和C++中类的静态成员变量有点类似。对于公有的类属性,在类外可以通过类对象和实例对象访问

    1、类属性

    class Person(object):
        name = "Tom" #公有的类属性
        __age = 12   #私有的类属性
    
    p = Person()
    
    print(p.name)        #正确
    print(Person.name)   #正确
            
    #print(p.__age)        #错误,不能再类外通过实例变量访问类的私有属性
    #print(Person.__age) #错误,不能再类外通过类对象访问类的私有属性

    运行结果为:Tom、Tom

    2、实例属性(对象属性)

    class Person(object):
        address = "广州"
        def __init__(self):
            self.name = "Se7eN_HOU"
            self.age = 29  
    
    p = Person()
    p.age = 18 #实例属性
    print(p.name)    #正确
    print(p.address) #正确。实例对象可以访问类属性
    print(p.age)     #正确
    
         
    print(Person.address)   #正确
    #print(Person.name)   #错误,类不能访问实例属性
    #print(Person.age)  #错误,类不能访问实例属性

    运行结果为:

    Se7eN_HOU
    广州
    18
    广州

    3、通过实例去修改类属性

    class Person(object):
        address = "广州" #类属性
        
    p = Person()
    
    print(p.address)    #正确
    print(Person.address) #正确
    
    print("-------分界线--------")
    
    p.address = "北京"
    print(p.address)
    print(Person.address)
    
    print("-------分界线--------")
    
    Person.address = "上海"
    print(p.address)
    print(Person.address)

    运行结果为:

    广州
    广州
    -------分界线--------
    北京
    广州
    -------分界线--------
    北京
    上海

    说明:

    • 如果需要在类外修改类属性,必须通过类对象去引用然后进行修改。
    • 如果通过实例对象去引用,会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性。
    • 如果通过实例对象去引用该类的类的属性,实例属性其实会重新创建一个新的属性。

    七、类方法

    类方法:是类对象所拥有的方法,需要用修饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数(当然可以用其他名称的变量作为其第一个参数,但是大部分人都习惯以’cls’作为第一个参数的名字,就最好用’cls’了),能够通过实例对象和类对象去访问。

    class Person(object):
        country = "china"
    
        @classmethod
        def getCountry(cls):
            return cls.country
    
    p = Person()
    print(p.getCountry()) #正确,实例对象可以调用类方法
    print(Person.getCountry())

    运行结果为:china、china

    类方法还有一个用途就是可以对类属性进行修改:

    class Person(object):
        country = "china"
    
        @classmethod
        def getCountry(cls):
            return cls.country
    
        @classmethod
        def setCountry(cls,newCountry):
            cls.country = newCountry
    
    p = Person()
    print(p.getCountry()) #正确,实例对象可以调用类方法
    print(Person.getCountry())
         
    p.setCountry("CHINA")
    print(p.getCountry())
    
    Person.setCountry("中国")
    print(Person.getCountry())

    运行结果为:

    china
    china
    CHINA
    中国

    结果显示在用类方法对类属性修改之后,通过类对象和实例对象访问都发生了改变

    八、静态方法

    静态方法:需要通过修饰器@staticmethod来进行修饰,静态方法不需要多定义参数

    class Person(object):
        country = "china"
    
        @staticmethod
        def getCountry():
            return Person.country
    
    p = Person()
    print(p.getCountry())
    print(Person.getCountry())

    运行结果为:china、china

    总结:

    实例方法:

    • 定义:第一个参数必须是实例对象,该参数名一般约定为“self”,通过它来传递实例的属性和方法(也可以传类的属性和方法);
    • 调用:只能由实例对象调用。

    类方法:

    • 定义:使用装饰器@classmethod。
    • 第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法);
    • 调用:实例对象和类对象都可以调用。

    静态方法:

    • 定义:使用装饰器@staticmethod。参数随意,没有“self”和“cls”参数,但是方法体中不能使用类或实例的任何属性和方法;
    • 调用:实例对象和类对象都可以调用。
  • 相关阅读:
    2013年工作中用到的10个命令:11-20
    2013年工作中用到的10个命令:11-20
    2013年工作中用到的10个命令:1-10
    OpenJDK源码研究笔记(十):枚举的高级用法,枚举实现接口,竟是别有洞天
    OpenJDK源码研究笔记(十):枚举的高级用法,枚举实现接口,竟是别有洞天
    Java实现 LeetCode 240 搜索二维矩阵 II(二)
    Java实现 LeetCode 239 滑动窗口最大值
    Java实现 LeetCode 239 滑动窗口最大值
    Java实现 LeetCode 239 滑动窗口最大值
    Java实现 LeetCode 238 除自身以外数组的乘积
  • 原文地址:https://www.cnblogs.com/Se7eN-HOU/p/10698127.html
Copyright © 2020-2023  润新知