4.不会吧不会吧,你居然还没有对象
*4.1 面向对象的三大特征
注:本小节带 *,不需要进行学习,可以简单进行了解
⛲️ 封装:提高程序的安全性
将数据(属性)和行为(方法)包装到类对象中。在方法内部对属性进行操作,在类对象的外部调用方法。这样,无需关心方法内部的具体实现细节,从而隔离了复杂度。
在Python中没有专门的修饰符用于属性的私有,如果该属性不希望在类对象外部被访问,前边使用两个_ 。
继承:提高代码的复用性
多态:提高程序的可扩展性和可维护性
接下来,我们来具体介绍这三大特征
4.2 封装
🚩将数据(属性)和行为(方法)包装到类对象中。在方法内部对属性进行操作,在类对象的外部调用方法。这样,无需关心方法内部的具体实现细节,从而隔离了复杂度。
❗️ 注:下面的代码使用了 __init__() 方法,后续会有讲解,读者这里只需要知道 __init__() 的含义是把输入的值进行赋值即可(对创建的对象进行初始化)
# 博主:辰chen # 博客地址:https://chen-ac.blog.csdn.net/ # 开发时间:2022/1/1 0:39 # 欢迎大家关注AIoT相关博客~ class Car: def __init__(self, brand): self.brand = brand def start(self): print('车启动了') car = Car('Veneno') print(car.brand) car.start()
在Python中没有专门的修饰符用于属性的私有,如果该属性不希望在类对象外部被访问,前边使用两个_
# 博主:辰chen # 博客地址:https://chen-ac.blog.csdn.net/ # 开发时间:2022/1/1 0:49 # 欢迎大家关注AIoT相关博客~ class Student: def __init__(self, name, age): self.name = name self.__age = age # 年龄不希望在外部被使用,所以加了两个_ def show(self): print(self.name, self.__age) stu = Student('辰chen', 19) stu.show() # 在类的外部使用 name 和 age try: print(stu.__age) except AttributeError as e: print(e)
现在有小淘气出来了:真的没有方法访问 age 了么?
其实还是有的,见下述代码:
❗️ 注:下面的代码使用了 __init__() 方法,后续会有讲解,读者这里只需要知道 __init__() 的含义是把输入的值进行赋值即可(对创建的对象进行初始化)
# 博主:辰chen # 博客地址:https://chen-ac.blog.csdn.net/ # 开发时间:2022/1/1 0:49 # 欢迎大家关注AIoT相关博客~ class Student: def __init__(self, name, age): self.name = name self.__age = age # 年龄不希望在外部被使用,所以加了两个_ def show(self): print(self.name, self.__age) stu = Student('辰chen', 19) stu.show() # 在类的外部使用 name 和 age try: print(stu.__age) except AttributeError as e: print(e) # 在类的外部可以通过 _Student__age进行访问(不推荐!!!) print(stu._Student__age)
4.3 继承
🚩我们通过一张图来介绍父类和子类:
上面的图中,我们可以说动物是爬行动物和哺乳动物的父类,即爬行动物和哺乳动物是动物的子类;鳄鱼、蛇的父类是爬行动物,爬行动物的子类是鳄鱼和蛇;老虎、猴子、狼的父类是哺乳动物,哺乳动物的子类为老虎、猴子、狼。
不难看出,父类中拥有一些性质是子类中所共有的,所以我们在定义子类的时候就不必写的那么麻烦,只需要从父类那边继承即可。
Python 中可以单继承,也可以多继承,其语法格式为:
class 子类类名(父类1, 父类2, ...): pass
如果一个类没有继承任何类,则默认继承object,比如我们之前学习中的代码其实就是默认继承 object。
定义子类时,必须在其构造函数中调用父类的构造函数。
❗️ 注:下面的代码使用了 __init__() 方法,后续会有讲解,读者这里只需要知道 __init__() 的含义是把输入的值进行赋值即可(对创建的对象进行初始化)
# 博主:辰chen # 博客地址:https://chen-ac.blog.csdn.net/ # 开发时间:2022/1/1 1:28 # 欢迎大家关注AIoT相关博客~ class Person(object): 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, stuNum): self.name = name self.age = age self.stuNum = stuNum class Teacher(Person): def __init__(self, name, age, teaNum): self.name = name self.age = age self.teaNum = teaNum stu = Student('辰chen', 19, '171519') stu.info() tea = Teacher('晶姐', 30, '52519') tea.info()
下面简单介绍多继承:
# 博主:辰chen # 博客地址:https://chen-ac.blog.csdn.net/ # 开发时间:2022/1/1 1:49 # 欢迎大家关注AIoT相关博客~ class A(object): pass class B(object): pass class C(A, B): # C 有两个父类: A 和 B pass
4.4 方法重写
🚩所谓方法重写其实就是当我们父类的某个属性或方法无法满足我们子类的需求,我们可以在子类中对其(方法体)进行重新编写,例如我们在 4.3 继承 中单继承的例子,我们在 Person 类中定义的 info 方法只能输出名字和年龄,但是学生和老师都有属于自己的学生编号和教职工编号,这些属性是子类中所特有的,但我们在调用子类中继承父类中的 info 方法时发现只能输出姓名和年龄,这不是我们想要的我,针对以上这种情况我们就可以使用方法重写。对于方法重写就是在子类中定义一个和父类中相同名称的函数体(可理解为覆盖)。
如上图所示,当你在子类中重写方法时在PyCharm中会有提示。
❗️ 注:下面的代码使用了 __init__() 方法,后续会有讲解,读者这里只需要知道 __init__() 的含义是把输入的值进行赋值即可(对创建的对象进行初始化)
# 博主:辰chen # 博客地址:https://chen-ac.blog.csdn.net/ # 开发时间:2022/1/1 8:28 # 欢迎大家关注AIoT相关博客~ class Person(object): 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, stuNum): self.name = name self.age = age self.stuNum = stuNum def info(self): print(self.stuNum) class Teacher(Person): def __init__(self, name, age, teaNum): self.name = name self.age = age self.teaNum = teaNum def info(self): print(self.teaNum) stu = Student('辰chen', 19, '171519') stu.info() tea = Teacher('晶姐', 30, '52519') tea.info()
哎,问题又来了,我们成功输出了学号和教师编号,但是姓名和年龄却没有了,这就是我上面说过的覆盖,可以简单的理解成子类和父类同时定义了一个方法体,我们在实例化对象对方法进行调用的时候,优先调用子类的方法,我们如果想把输出姓名,年龄,编号都输出,当然可以在子类的方法中写成:
def info(self): print(self.name, self.age, self.stuNum) def info(self): print(self.name, self.age, self.teaNum)
但这显然是不够简洁美观的,我们父类中的方法消失了么?其实并没有消失,我们只不过是优先调用了子类的方法。我们可以用super().xxx()去调用父类中被重写的方法。这样可以精简我们的代码:
❗️ 注:下面的代码使用了 __init__() 方法,后续会有讲解,读者这里只需要知道 __init__() 的含义是把输入的值进行赋值即可(对创建的对象进行初始化)
# 博主:辰chen # 博客地址:https://chen-ac.blog.csdn.net/ # 开发时间:2022/1/1 8:28 # 欢迎大家关注AIoT相关博客~ class Person(object): 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, stuNum): self.name = name self.age = age self.stuNum = stuNum def info(self): super().info() print(self.stuNum) class Teacher(Person): def __init__(self, name, age, teaNum): self.name = name self.age = age self.teaNum = teaNum def info(self): super().info() print(self.teaNum) stu = Student('辰chen', 19, '171519') stu.info() tea = Teacher('晶姐', 30, '52519') tea.info()
显然,父类中有 __init__() 方法,可以传入姓名和年龄两个参数,子类中也有 __init()__ 方法,这其实就是在重写父类中的方法,我们同样可以按照上述去调用父类中的 __init__() 方法,从而可以精简我们的代码:
❗️ 注:下面的代码使用了 __init__() 方法,后续会有讲解,读者这里只需要知道 __init__() 的含义是把输入的值进行赋值即可(对创建的对象进行初始化)
# 博主:辰chen # 博客地址:https://chen-ac.blog.csdn.net/ # 开发时间:2022/1/1 8:28 # 欢迎大家关注AIoT相关博客~ class Person(object): 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, stuNum): super().__init__(name, age) self.stuNum = stuNum def info(self): super().info() print(self.stuNum) class Teacher(Person): def __init__(self, name, age, teaNum): super().__init__(name, age) self.teaNum = teaNum def info(self): super().info() print(self.teaNum) stu = Student('辰chen', 19, '171519') stu.info() tea = Teacher('晶姐', 30, '52519') tea.info()