【Python】第六篇:封装、继承、多态——面向对象的三大特征

💖星光不问赶路人,时光不负有心人!💖

系列文章目录🍁

第一篇:基础语法与结构 整理万字,秃头的路上,我们一起成为卷王
第二篇:Python四大内置数据结构列表、字典、元组、集合看这一篇完全够用
第三篇:字符串与函数,越学越上头的python,你确定不来看看?
第四篇:Bug——程序员的一生之敌,先别急着写Bug,快来学学怎么在Python中调教它
第五篇:类与对象 找对象不积极,思想有问题


文章目录

  • 系列文章目录🍁
  • 🌴前言
  • 🌿零、面向对象的三大特征
  • 🌿一、封装
  • 🌿二、继承
  • 1.继承
  • 2.方法重写
  • 3.object类
  • 🌿三、多态
  • 🌿四、特殊方法和特殊属性(***)
  • 1.特殊属性
  • 2.特殊方法
  • 🌿五、类的赋值与拷贝(***)
  • 1.类的赋值
  • 2.类的浅拷贝
  • 3.类的深拷贝
  • 🌴总结

  • 🌴前言

    大家好,我是小沐!😃编程路上一个人可能走的更快,但一群人才能走得更远,关注小沐一起学习不迷路!今天分享的是 面向对象的三大特征——封装、继承、多态的有关知识,话不多说,秃头走起——>冲冲冲👊👊👊!!!


    🌿零、面向对象的三大特征

    封装、继承和多态是面向对象的三大特征。
    封装是为了提高程序的安全性
    继承是为了提高代码的复用性
    多态是为了提高程序的可扩展性和可维护性
    值得一提的是,这三大特征与语言本身无关,这是一种面向对象编程思想。*

    🌿一、封装

    什么是封装?
    其实封装就是包装,例如银行里的ATM机里放着钱,机器包装着钱,而我们根本不知道钱在机器的哪个位置放着,我们只能通过合适的方式去取钱。这样就提高了钱的安全性。
    写程序时的封装也是一样的,我们将数据(属性)和行为(方法)包装到类对象中。而在方法内部对属性进行操作,在类对象的外部调用方法。这样我们只需要用合适的方式去用它,而不用关心刚方法时如何具体实现的。

    在Python中没有专门的修饰符用于属性的私有,如果不希望该属性在类对象外部被访问,可在前边使用两个"_"

    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()
    print(stu.name)
    #print(stu.__age) #报错
    print(dir(stu))  #可查看类内的属性和方法
    print(stu._Student__age)  #在类的外部可通过_Student__age访问
    

    注意:如果一定要在类外部访问,可通过_Student__age访问,但大家都比较自觉,人家都不让你问访问了,你就别这么访问了😤

    🌿二、继承

    1.继承

    简单来说继承就是定义子类,子类继承父类的属性和方法。

    语法:
    class 子类类名(父类1,父类2…):
    pass

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

    #定义父类
    class Person(object): #object可写可不写
        def __init__(self,name,age):
            self.name=name
            self.__age=age #前边加两_表示不希望在类外部被访问
        def show(self):
            print(self.name,self.__age)
    #定义子类
    class Student(Person):
        def __init__(self,name,age,score):
            super().__init__(name,age) #调用父类的构造函数
            self.score=score   #自己额外的属性
    #调用
    stu=Student('苏沐',20,99)
    stu.show()
    

    2.方法重写

    上述代码中由于我们继承了Person类,调用show时只输出name和age,我们需要它还输出score就需要方法重写。
    如果子类对继承自父类的某个属性或方法不满意,可以在子类中对其方法进行重新编写;
    子类重写后的方法中,可以通过super().xxx()调用父类中被写过的方法。

    #定义父类
    class Person(object): #object可写可不写
        def __init__(self,name,age):
            self.name=name
            self.__age=age #前边加两_表示不希望在类外部被访问
        def show(self):
            print(self.name,self.__age)
    #定义子类
    class Student(Person):
        def __init__(self,name,age,score):
            super().__init__(name,age) #调用父类的构造函数
            self.score=score   #自己额外的属性
        def show(self):   #方法重写
            super().show()   
            print(self.score)
    #调用
    stu=Student('苏沐',20,99)
    stu.show()
    

    3.object类

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

    class Student:
        def __init__(self,name,age):
            self.name=name
            self.age=age
        def __str__(self):
            return '我的名字是{0},今年{1}岁'.format(self.name,self.age)
    stu=Student('苏沐',20)
    print(dir(stu))  #查看对象信息
    print(str(stu))  #没重写__str__前输出对象地址,重写后输出你重写返回的内容
    print(stu)       #和上面一句等价,直接输出的话默认调用__str__()方法
    print(type(stu))
    

    🌿三、多态

    很多人说,Python中没有多态的概念,因为Python中的变量是没有数据类型的。
    其实不然,虽然Python中变量没有数据类型,但是仍然具备多态的特征。

    Python中的多态指的是,在运行过程中根据变量所引用对象的类型,动态的决定调用哪个类对象中的方法。

    class Animal(object):
        def run(self):
            print('动物会跑')
    class Dog(Animal):
        def run(self):
            print('狗会跑')
    class Cat(Animal):
        def run(self):
            print('猫会跑')
    class Person():
        def run(self):
            print('人会跑')
    
    #定义一个函数
    def fun(obj):
        obj.run()
    #调用函数
    fun(Animal())
    fun(Cat())
    fun(Dog())
    fun(Person())
    

    这里Animal、Cat、Dog、Person都调用了run方法,Cat和Dog是对Animal中run的重写,很容易理解,但是Person中的run与其他三个中的是并列的,调用的时候就看传入对象的类型属于哪个就调用哪个。这是与其他编程语言所不同的,我们称为“鸭子类型”。
    Python是一种动态的语言。

    静态语言与动态语言关于多态的区别:
    静态语言实现多态的三个必要条件:
    继承、方法重写、父类引用指向子类对象
    动态语言的多态称为“鸭子类型”,当一只鸟走路,游泳,啄食等行为都像鸭子的时候,我们认为它就是鸭子。我们不关心对象是什么类型,只关心对象的行为(方法)。

    🌿四、特殊方法和特殊属性(***)

    以两个下划线开始和结束的如__xxx__称为特殊属性和特殊方法。

    1.特殊属性

    #特殊属性__dict__获得类对象或实例化对象所绑定的所有属性和方法的字典
    #dir(object)可查看object中的属性、方法
    class A:
        pass
    class B:
        pass
    class C(A,B):
        def __init__(self,name,age):
            self.name=name
            self.age=age
    #创建C类对象
    c=C('苏沐',20)
    #查看实例对象的属性字典,方法是在类对象中的,实例对象只能调用
    print(c.__dict__)# {'name': '苏沐', 'age': 20}
    #查看类对象的属性和方法字典
    print(C.__dict__) #{'__module__': '__main__', '__init__': <function C.__init__ at 0x000001CB9F854D30>, '__doc__': None}
    
    print(c.__class__) #输出对象所属的类 <class '__main__.C'>
    print(C.__bases__) #输出C类的父类元组 (<class '__main__.A'>, <class '__main__.B'>)
    print(C.__base__) #输出类的第一个父类 <class '__main__.A'>
    print(C.__mro__) #输出类的层次结构
    print(A.__subclasses__()) #输出A的子类
    

    2.特殊方法

    #特殊方法
    # __add__ 通过重写__add__方法,可使自定义对象具有+功能
    # 通过重写__len__方法,让内置函数len()的参数可以是自定义类型
    
    a=10
    b=20
    c=a+b #实际过程为下一行代码
    d=a.__add__(b)
    print(c,d)
    
    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('苏沐')
    stu2=Student('秃头')
    stu=stu1+stu2  #重定义__add__后就不会报错了,因为在Student中编写了特殊方法
    stu=stu1.__add__(stu2)
    print(stu)
    
    print(len(stu))
    
    #__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)))
    #创建实例对象
    p1=Person('苏沐',20)
    print('p1这个Person类的实例对象的id为{0}:'.format(id(p1)))
    


    执行过程为:在创建实例对象的过程中将Student传给cls,然后object中创建一个对象obj,传给init方法中的self初始化,完成后赋值给p1.所以后输出的三个的id地址都是一样的。

    总的来说,我们想让该方法实现哪些内容,该方法的方法体就由我们来写。许多的特殊方法都对应于一些内置函数。

    🌿五、类的赋值与拷贝(***)

    1.类的赋值

    只是形成了两个变量,实际上还是指向同一个实例对象。

    class A():
        pass
    a1=A()
    a2=a1
    print(id(a1)) #2364867875104
    print(id(a2)) #2364867875104
    

    2.类的浅拷贝

    Python拷贝一般都是浅拷贝,拷贝时,对象包含的子对象内容不拷贝,因此,源对象与拷贝对象会引用同一个子对象

    import copy
    a2=copy.copy(a1)
    

    3.类的深拷贝

    使用copy模块的deepcopy函数,递归拷贝对象中包含的子对象,源对象和拷贝对象所有的子对象也不相同

    #深拷贝
    import copy
    a3=copy.deepcopy(a1)
    

    🌴总结

    今日分享到此结束👊👊👊,由于笔者还在求学之路上辗转徘徊🏃,水平有限,文章中可能有不对之处,还请各位大佬指正🙏,祝愿每一个热爱编程的人都能实现追求,考研上岸进大厂,熬夜秃头卷中王。最后欢迎关注小沐,学习路上不迷路!😜

    来源:小沐想秃头

    物联沃分享整理
    物联沃-IOTWORD物联网 » 【Python】第六篇:封装、继承、多态——面向对象的三大特征

    发表评论