继承的含义
面向对象中继承是用来描述类与类之间数据的从属关系,通过继承可以减少代码冗余,提升开发效率,同样也支持多继承
基本使用
class A: # 被继承的类称为父类或者基类
name = 'from A'
class B(A): # 继承别人的类称为子类或者派生类
pass
print(B.name)
# from A
"""在python中一个类可以同时继承多个父类"""
class A:
nameA = 'from A'
class B:
nameB = 'from B'
class C:
nameC = 'from C'
class MyClass(A, B, C):
pass
print(MyClass.nameA)
# from A
print(MyClass.nameB)
# from B
print(MyClass.nameC)
# from C
继承的本质
class Person: # 多个类相同数据和功能的结合体,父类
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
class Teacher(Person): # 多个对象相同数据和功能的结合体,子类
def teach(self):
print(f'{self.name}老师正在讲课')
class Student(Person): # 多个对象相同数据和功能的结合体,子类
def study(self):
print(f'{self.name}正在在学习')
obj_1 = Student('kevin', 22, 'male') # 数据与功能的结合体,对象
obj_1.study()
# kevin正在在学习
继承的分类
python2存在经典类与新式类
- 经典类:在 python2.2 之前⼀直使⽤的是经典类,经典类在基类的根什么都不写
- 新式类: 在 python2.2 之后出现了新式类,新式类的特点是基类的根,
object
类
class A:
pass
class B(object):
pass
print(A.__base__)
# 空的
print(B.__base__)
# <class 'object'>
python3只有新式类
- 新式类:python3中使⽤的都是新式类,如果基类谁都不继承,那这个类会默认继承 object
# 有时候我们在定义类的时候会习惯性的写
class MyClass(object):
pass
# 为了兼容python2和python3
名字的查找顺序(继承)
核心:先从对象自己的名称空间中查找,没有择取产生对象的类中查找,如果还没有并且类有父类则去父类中查找,以此往复下去
对象 >>> 类 >>> 父类
记住一点,名字的查找顺序永远都是,先从当前对象自身开始查找
单继承
class A:
def func_1(self):
print('from A.func_1')
def func_2(self):
print('from A.func_2')
class MyClass(A):
def func_1(self):
print('from MyClass.func_3')
obj = MyClass()
obj.func_1() # 先找自己,在找继承
# from MyClass.func_3
obj.func_2() # 自己没有,在找继承
# from A.func_2
class A:
name = 'from A'
class B(A):
name = 'from B'
class C(B):
name = 'from C'
class MyClass(C):
name = 'from MyClass' # 有则找MyClass里面的name
obj = MyClass()
obj.name = '我自己的name'
print(obj.name) # 先找自己,在找调用的类,类里没有,在找父类一直往上推
# 我自己的name
多继承
普通多继承
class A:
# name = 'a'
pass
class B:
name = 'b'
class C:
name = 'c'
class MyClass(A,B,C):
# name = 'MyClass'
pass
obj = Myclass()
print(obj.name)
# b
非菱形多继承
父类中名字的查找顺序按照继承时从左往右依次查找,如果多个父类还有分类,那么遵循”深度优先”
class E:
name = 'from E'
class F:
# name = 'from F'
pass
class D:
# name = 'from D'
pass
class A(D):
# name = 'from A'
pass
class B(E):
# name = 'from B'
pass
class C(F):
# name = 'from C'
pass
class MyClass(A,B,C):
# name = 'from MyClass'
pass
obj = MyClass()
# obj.name = 'from obj'
print(obj.name)
菱形多继承
父类中名字的查找顺序就是按照继承时从左往右依次查找,如果多个父类还有分类 那么遵循”广度优先”
class M:
name = 'from M'
class E(M):
name = 'from E'
pass
class F(M):
name = 'from F'
pass
class D(M):
# name = 'from D'
pass
class A(D):
# name = 'from A'
pass
class B(E):
name = 'from B'
pass
class C(F):
# name = 'from C'
pass
class MyClass(A,B,C):
# name = 'from MyClass'
pass
obj = MyClass()
print(obj.name)
# from B
派生类用法(子类)
在写的子类需要使用父类的方法,并且还需要基于该方法做扩展,这样的子类称为派生类(本质还是子类),使用关键字super
关键字来实现
class Person:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
class Teacher(Person):
def __init__(self, name, age, gender, salary, hobby):
# 用了Person类里面的__init__方法
# super(Teacher,self).__init__(name, age, gender) # 子类调用父类的完整语法
super().__init__(name, age, gender) # 子类调用
# 自己还要添加一个额外的东西
self.salary = salary
self.salary = hobby
class Student(Person):
def __init__(self, name, age, gender, stu_id, class_id):
# 用了Person类里面的__init__方法
super().__init__(name, age, gender)
# 自己还要添加一个额外的东西
self.stu_id = stu_id
self.class_id = class_id
obj_1 = Teacher('kevin', 22, 'male', 1000, 'run')
obj_2 = Student('kevin', 22, 'male', 123, 123)
print(obj_1.__dict__)
# {'name': 'kevin', 'age': 22, 'gender': 'male', 'salary': 'run'}
print(obj_2.__dict__)
# {'name': 'kevin', 'age': 22, 'gender': 'male', 'stu_id': 123, 'class_id': 123}
派生功能前瞻
class MyClass(list):
def append(self, args):
if args == 123:
print("数字123不能追加")
return
super(MyClass, self).append(args)
print(f"{self}")
obj = MyClass()
obj.append(111)
# [111]
obj.append(222)
# [111, 222]
obj.append(123)
# 数字123不能追加
obj.append(333)
# [111, 222, 333]
派生实际应用
前言
json
不能序列化python
所有的数据类型,只能是一些基本数据类型,通过继承的方式将,研究并重写json
序列化方法
import datetime
import json
times = datetime.date.today()
print(type(times))
# <class 'datetime.date'>
json.dumps(times)
# TypeError: Object of type 'date' is not JSON serializable
研究
研究函数dumps
参数中有一个叫cls
,如果这个参数为None
则等于JSONEncoder
,查看后发现JSONEncoder
是一个类,类里有一个方法叫default
,正是报错的原因
实现
写一个类去继承JSONEncoder
,然后重新default
方法
import datetime
import json
class MyJsonEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, datetime.datetime):
return o.strftime('%Y-%m-%d %X')
elif isinstance(o, datetime.date):
return o.strftime('%Y-%m-%d')
return super().default(o) # 调用父类的default(让父类的default方法继续执行,防止有其他额外操作)
d = {'t1': datetime.datetime.today(), 't2': datetime.date.today()}
res = json.dumps(d, cls=MyJsonEncoder) # 指定cls执行为我们写的类
print(res)
# {"t1": "2022-04-09 17:33:36", "t2": "2022-04-09"}