zoukankan      html  css  js  c++  java
  • Python学习系列之面向对象的三大特征(封装、继承、多态)(二十七)

    面向对象的三大特征

    1、封装:提高程序的安全性

    • 将数据(属性)和行为(方法)包装到类对象中。在方法内部对属性进行操作,在类对象的外部调用方法。这样,无需关心方法内部的具体实现细节,从而隔离了复杂度。
    • 在Python中没有专门的修饰符用于属性的私有,如果该属性不希望在类对象外部被访问,前边使用两个“_”。

    2、继承:提高代码的复用性

    3、多态:提高程序的可扩展性和可维护性

    一、封装

    一个类就是一个封装,将类的属性、变量、方法全部封装在类里面

    代码示例:

    '''封装'''
    class Car:
        def __init__(self,brand):
            self.brand=brand
        def start(self):
            print('汽车已启动....')
    
    car=Car('宝马X5')
    car.start()
    print(car.brand)
    

      执行结果:

     如果属性不想在类外部使用,则只需要在属性前加"__",示例代码如下:

    #对象不想在类外部使用,在属性前使用__进行标记
    class Student:
        def __init__(self,name,age):
            self.name=name
            self.__age=age
    
        def show(self):
            print(self.name,self.__age)
    
    stu=Student('张三',20)
    stu.show()
    #在类之外使用name和age
    print(stu.name)
    # print(stu.__age)    #直接使用会报错AttributeError: 'Student' object has no attribute '__age'
    #print(dir(std))
    print(stu._Student__age)    #此种方法调用,能正确执行并返回
    

      执行结果:

      说明:__age可以在外部被使用,此种写法就是告诉开发者不要在外部使用该属性

    二、继承及其实现方式

    继承

    • 语法格式

        class 子类类名(父类1,父类2...):

          pass

    • 如果一个类没有继承任何类,则默认继承Object
    • Python支持多继承
    • 定义子类时,必须在其构造函数中调用父类的构造函数

    代码示例:

    '''继承'''
    class Person():     #父类
        def __init__(self,name,age):
            self.name=name
            self.age=age
        def info(self):
            print(self.name,self.age)
    
    class Student(Person):      #子类
        def __init__(self,name,age,stu_no):
            super().__init__(name,age)
            self.stu_no=stu_no
    
    class Teacher(Person):      #子类
        def __init__(self,name,age,tea_no):
            super().__init__(name,age)
            self.tea_no=tea_no
    
    stu=Student('张三',20,'1001')
    teacher=Teacher('李四',30,10)
    stu.info()      #info方法是从父类Person类继承过来的
    teacher.info()
    

      执行结果:

      说明:stu调用的info()方法都是从父类中继承过来的

    上面示例中的继承关系图如下:

      

    • Python支持多继承
    '''多继承'''
    class A():
        pass
    
    class B():
        pass
    
    class C(A,B):
        pass
    

      上述代码的示意图:

     说明:class C(A,B)表示C类既继承了A类,也继承了B类

    三、方法重写

    方法重写

    • 如果子类对继承父类的某个属性或方法不满意,可以在子类中对齐(方法体)进行重新编写
    • 子类重写后的方法中可以通过super().xxx()调用父类中被重写的方法

    要输出学生的学生编号和教师的教龄,示例代码:

    '''重写
    重写父类的方法'''
    class Person():     #父类
        def __init__(self,name,age):
            self.name=name
            self.age=age
        def info(self):
            print(self.name,self.age)
    
    class Student(Person):      #子类
        def __init__(self,name,age,stu_no):
            super().__init__(name,age)
            self.stu_no=stu_no
        def info(self):     #重写了父类的info()方法
            super().info()
            print(self.name+'的学生编号是:'+self.stu_no)
    
    class Teacher(Person):      #子类
        def __init__(self,name,age,teachofyear):
            super().__init__(name,age)
            self.teachofyear=teachofyear
        def info(self):     #重写了父类的info()方法
            super().info()
            print(self.name+'的教龄是:',self.teachofyear)
    
    stu=Student('张三',20,'1001')
    teacher=Teacher('李四',30,10)
    stu.info()
    print('-----------------------')
    teacher.info()
    

      执行结果:

     说明:重写是子类在自己的类中重新定义父类的方法,即在子类中定义和父类一样的方法名的方法,然后添加自己的业务代码,这段示例代码中,Student类和Teacher类重写了父类的info()方法,重写父类的方法时需要使用super().info()来对父类方法进行调用,学生编号和教龄是通过重写父类方法来输出的

    四、object类

     object类

    • object类是所有类的父类,因此所有类都有object类的属性和方法。
    • 内置函数dir()可以查看指定对象所有的属性
    • object类有一个__str__()方法,用户返回一个对于“对象的描述”,对应于内置函数str()经常用于print()方法,帮我们查看对象的信息,所以我们经常会对__str__()进行重写

    1. 查看object类的所有属性和方法

    class Student:
        pass
    
    stu=Student()
    print(dir(stu))
    

      执行结果:

     说明:使用dir()方法可以查看Object类的所有属性和方法,stu是Student类的实例对象,Student类默认继承自Object类,所以执行dir(stu)会将object类的属性和方法全部查询出来,这些属性和方法都不是Student类里定义的

    2. __str__()方法,用户返回一个对于“对象的描述”

    class Student:
        pass
    
    stu=Student()
    print(stu)
    

      执行结果:

     说明:print(stu) 调用的是object类的 __str__()方法,输出的是stu这个对象的描述,包括对象类型和内存地址

    我们可以通过重写__str__()方法,来输出自己的描述

    '''重写__str__()方法来返回自己的描述'''
    class Student:
        def __init__(self,name,age):
            self.name=name
            self.age=age
        def __str__(self):      #重写object类的__str__()方法
            return '我的名字是{0},今年{1}岁'.format(self.name,self.age)
    
    stu=Student('张三',20)
    # print(dir(stu))
    print(stu)
    print(type(stu))
    

      执行结果:

     说明:__str__()方法默认返回的是对象的描述,在Student类中重写了object的__str__()方法,返回了自己的描述

    五、多态的实现

     示例代码:

    '''多态'''
    class Animal:
        def eat(self):
            print('动物会吃')
    
    class Dog(Animal):
        def eat(self):
            print('狗吃骨头....')
    
    class Cat(Animal):
        def eat(self):
            print('猫吃鱼')
    
    class Person:
        def eat(self):
            print('人吃五谷杂粮')
    
    #定义一个函数
    def fun(obj):
        obj.eat()
    
    #开始调用函数
    fun(Dog())
    fun(Cat())
    fun(Animal())
    print('--------------')
    fun(Person())
    

      执行结果:

     说明:代码中Cat类和Dog类继承了Animal类,重写了Animal中的eat()方法,所以当输入Dog和Cat的对象时,会去执行Dog类和Cat类中的eat方法,但是Person类并没有继承Animal类,只是因为它有eat()方法,所以也会去执行Person类中的eat()方法,这就是和其它变成语言不一样的地方,这叫鸭子类型,Python是一门动态语言,可以动态地去绑定属性和绑定方法。

    什么是动态语言

    • 动态语言的多态崇尚“鸭子类型”,当看到一只鸟走起来像鸭子,游泳起来像鸭子,收起来像鸭子,那么这只鸟就可以被称为鸭子。在鸭子类型中,不需要关系对象是什么类型,到底是不是鸭子,只关心对象的行为。

    静态语言和动态语言的区别:

    静态语言实现多态的三个必要条件

    • 继承
    • 方法重写
    • 父类引用指向子类对象

     java是静态语言,实现多态必须满足继承、方法重写、父类引用指向子类对象

    六、特殊属性和特殊方法

      名称 描述
    特殊属性 __dict__ 获得类对象或示例对象所绑定的所有属性和方法的字典
    特殊方法 __len__() 通过重写__len__()方法,让内置函数len()的参数可以是自定义类型
    __add__() 通过重写__add__()方法,可使用自定义对象具有“+”功能
    __new__() 用于创建对象
    __init__() 对创建的对象进行初始化

     1. __add__()

    '''__add__'''
    a=20
    b=100
    c=a+b   #两个整数类型的对象的相加操作
    print(c)
    d=a.__add__(b)
    print(d)
    

      执行结果:

      说明:当计算a+b时,底层其实执行的是a.__add__(b)

    练习:使两个字符串相加

    class Student:
        def __init__(self,name):
            self.name=name
    
    stu1=Student('张三')
    stu2=Student('李四')
    s=stu1+stu2
    print(s)
    

      执行结果:

     说明:stu1和stu2是两个字符串,不能直接进行相加操作

     如果要使两个字符串相加,则需要自己重新定义相加的方法

    class Student:
        def __init__(self,name):
            self.name=name
    
        def __add__(self, other):
            return self.name+other.name
    
    stu1=Student('张三')
    stu2=Student('李四')
    s=stu1+stu2    #实现了两个对象的加法运算(因为在Student类中,编写__add()__特殊的方法)
    print(s)
    s1=stu1.__add__(stu2)
    print(s1)
    

      执行结果:

      

    2.__len()__方法

    '''__len()__'''
    lst=[11,22,33,44]
    print(len(lst))     #len()是内置函数
    print(lst.__len__())
    

      执行结果:

      说明:使用len()和__len()__方法的执行结果一样,说明特殊方法__len()__和内置函数len()是对应的

    联系:输出字符串的长度

    '''__len()__'''
    class Student:
        def __init__(self,name):
            self.name=name
    
        def __add__(self, other):
            return self.name+other.name
    
        def __len__(self):
            return len(self.name)
    
    stu1=Student('jack')
    print(len(stu1))       #会报错,提示TypeError: object of type 'Student' has no len()
    #如果想要计算string类型的长度,则需要自己的手动写len()方法
    

      执行结果:

     3. new和init方法

    class Person(object):
        def __new__(cls, *args, **kwargs):
            print('__new__被调用执行了,cls的id值为{0}'.format(id(cls)))
            obj=super().__new__(cls)
            print('创建的对象的id为:{0}'.format(id(obj)))
            return obj
    
        def __init__(self,name,age):
            print('__init__被调用了,self的id值为:{0}'.format(id(self)))
            self.name = name
            self.age = age
    
    print('object这个类对象的id为:{0}'.format(id(object)))
    print('Person这个类对象的id为:{0}'.format(id(Person)))
    
    #创建Person类的实例对象
    p1=Person('张三',20)
    print('p1这个Person类的实例对象的id:{0}'.format(id(p1)))
    

      执行结果:

     说明:

  • 相关阅读:
    mac idea 更换主题
    记一次Sonarqube踩坑实录
    Mysql 常用数据类型
    Spring Cloud 整合分布式链路追踪系统Sleuth和ZipKin实战,分析系统瓶颈
    git clone克隆github仓库慢,问题解决
    SpringBoot 解决跨域问题
    Android 中的敏感信息泄露
    Drozer 测试 APP
    Drozer 安装踩坑日记
    安卓测试笔记--工具安装
  • 原文地址:https://www.cnblogs.com/wx170119/p/14470568.html
Copyright © 2011-2022 走看看