继承的含义

面向对象中继承是用来描述类与类之间数据的从属关系,通过继承可以减少代码冗余,提升开发效率,同样也支持多继承

基本使用

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"}
Last modification:April 9, 2022
如果觉得我的文章对你有用,请随意赞赏