继承详解
一、面向对象OPP(Object Oriented Programming)
1.1、什么是面向对象
Python中万物皆对象
面向对象是一种对现实世界理解和抽象的方法
面向对象的方法:封装、继承、多态
1.2、对象的基本概念
对象:
对象是存在的具体实体,具有明确定义的状态(属性)和行为(方法)
1.3、类
基本概念:
具有相同属性的方法和方法的一组对象的集合
类是对象的模板/图纸,可以规定对象的特征(属性和方法)
例:老师类、学生类、玩家类、管理员类 等等
1.4、类和对象的关系
类是抽象的概念。
对象是能够看得到、摸得着的具体实体。
二、继承的基本概念
当两个类存在相同的属性和方法,这个时候我们选择继承(Inheritance)。
优点:
父类定义公共内容,方便统一修改
整体减少了代码量
添加新类方便
三、继承的Python实现
继承实例:
需求:
1、定义一个People类为父类,属性:姓名、年龄、性别,方法:打印talk,“我是一个People类!”,和名字、年龄、性别信息。
2、定义一个Student(学生)类为字类,属性:姓名、年龄、性别、学生编号,方法:打印talk“name说:我是一个学生”,和名字、年龄、性别、学生编号信息。
3、定义一个Teacher(教师)类为字类,属性:姓名、年龄、性别、教师编号,方法:打印talk“name说我是一个老师”,和名字、年龄、性别、老师编号信息。
代码实现:
# 继承
class People:
# 用来继承的父类
def __init__(self,name,age,sex):
self.__name = name
self.__age = 0
self.set_age(age)
self.__sex = sex
def set_age(self, age):
if age<0 or age>100:
age = 18
else:
self.__age = age
def get_age(self, age):
return self.__age
def get_name(self):
return self.__name
def talk(self):
print("我是一个People类!")
def __str__(self):
a = "{}\t{}\t{}\t"
return a.format(self.__name, self.__age, self.__sex)
class Student(People):
def __init__(self,name,age,sex,s_id_num):
# 学生类的自己属性:学号
super().__init__(name,age,sex)
self.__s_id_num = s_id_num
def __str__(self):
return super().__str__() + str(self.__s_id_num)
def talk(self):
# 学生说的话:
print(self.get_name()+ "说:我是一名学生!")
class Teacher(People):
def __init__(self,name,age,sex,t_id_num):
# 老师类的自己属性:学号
super().__init__(name,age,sex)
self.__t_id_num = t_id_num
def __str__(self):
return super().__str__() + str(self.__t_id_num)
def talk(self):
# 老师说的话:
print(self.get_name()+ "说:我是一名老师!")
if __name__ == '__main__':
p1 = People("张三", 20, "男")
print("姓名\t年龄\t性别")
print(p1)
p1.talk()
s1 = Student("李四",15,"男","123456")
print("姓名\t年龄\t性别\t学号")
print(s1)
s1.talk()
t1 = Teacher("王老师",30,"女","666666")
print("姓名\t年龄\t性别\t教师号")
print(t1)
t1.talk()
打印结果:
姓名 年龄 性别
张三 20 男
我是一个People类!
姓名 年龄 性别 学生号
李四 15 男 123456
李四说:我是一名学生!
姓名 年龄 性别 教师号
王老师 30 女 666666
王老师说:我是一名老师!
父类构造和字类构造:
注意:
1、super().__ init__()调用父类的初始化方法
2、构造方法不可继承
3、父类私有属性的字类中不能直接访问
4、继承关系 - “是一种” is-a 关系:父类和字类之间必需存在is-a关系(也就是说,子类是父类的真子集)
四、覆盖方法
子类修改定义在父类中的方法实现
子类中的方法必须使用父类方法相同的方法头
如:
class People:
def talk(self):
print("我是People类!")
class Student(People):
def talk(self):
print("我是学生类!")
class Teacher(People):
def talk(self):
print("我是教师类!")
注意:
1、方法覆盖发生在通过继承而相关不同类中
2、方法覆盖必须具有相同的方法签名
3、__开头定义的私有方法不能被覆盖:如果子类中的方法在父类中是私有的,那么这两个方法是完全不相干的,即使这两个方法有相同的方法名
五、object类
5.1、object类的概念
Python中的所有类都继承自object类。
如果定义类时没有显式地指明父类,父类默认为object。
5.2、object类定义的方法
object类中定义的所有方法都有两条前导下划线和后置下划线。
方法 | 作用说明 |
---|---|
__ new__() | 当创建对象自动被调用 |
__ init__() | 随后调用初始化方法初始化这个对象 |
__ str__() | 返回一个描述对象的字符串 |
__ eq__() | 判断两个对象的相等性 |
如:
class People:
def __new__(cls, *args, **kwarges):
print("命名关键字参数:", str(args))
print("关键字参数:", str(kwargs))
def __init__(self, name, sex, ......, **kwargs):
self.name = name
self.age = kwargs["age"]
5.3、项目实例
需求: 运用object类。
代码实现:
# object
class People(object):
# The base class of the class hierarchy.
def __new__(cls, *args, **kwargs):
# 1、__new__()必须有返回值,这个返回值就是实例化出来的当前类的对象
# 2、如果__new__()方法最后没有正确的返回当前类cls的对象,那么后面的init方法就不会被调用
# 3、当实例化对象时,本方法会被编译器自动调用
print("__new__()被调用!")
print("命名关键字参数:", str(args))
print("关键字参数:", str(kwargs))
return object.__new__(People)
# 等价写法
# return super().__new__(People)
def __init__(self, name, age = 18, **kwargs):
self.__name = name
self.__age = age
# 初始化函数
print("__init__被调用!")
# 遍历字典
for key, value in kwargs.items():
# print(key, value)
# 将用户传入的关键字参数设置为本类的属性
self.__setattr__(key, value)
# 还可以这样写
# self.__age = kwargs["age"]
if __name__ == '__main__':
p1= People("张三",20,id_num = "123456")
print("身份编号为:",p1.id_num)
打印结果:
__new__()被调用!
命名关键字参数: ('张三', 20)
关键字参数: {'id_num': '123456'}
__init__被调用!
身份编号为: 123456