面向对象三大特性之继承

面向对象三大特性之继承

1、什么是继承

继承是一种新建类的方式,新建的类称为子类或者派生类,被继承的类称为父类、基类或者超类

在python中,一个子类可以继承多个父类,其他语言中,一个子类只能继承一个父类

2、继承的作用

减少类与类之间的代码冗余

子类可以继承父类的所有属性,因此继承可以解决类与类之间的代码冗余问题

3、如何实现继承

  1. 先确定谁是子类,谁是父类
  2. 在定义子类时语法:子类(父类):

子类可以通过 子类.__ bases__ 查看父类

4、如何寻找继承关系

确定谁是子类

确定谁是父类,先抽象再继承

​ 抽象总结出对象之间相似的部分,再总结出类

​ 抽象总结类之间相似的部分,再总结出父类

# 解决代码冗余
# 父类
class People:
    country = 'China'

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex


# 子类1
class Student(People):
    def learn(self):
        return '学习技能'


# 子类2
class Teacher(People):
    def teach(self):
        return '教书技能'
    
# 子类可以继承父类的属性
stu_obj = Student('shen', 18, 'male')
print(stu_obj.name, stu_obj.age, stu_obj.sex, stu_obj.country, stu_obj.learn()) # shen 18 male China 学习技能

tea_obj = Teacher('wang', 24, 'female')
print(tea_obj.name, tea_obj.age, tea_obj.sex, tea_obj.country, tea_obj.teach()) # wang 24 female China 教书技能

5、在继承的背景下,对象属性的查找顺序

程序的执行是从上往下执行的,父类必须定义在子类上面

在继承的背景下,对象的属性查找顺序:

  1. 先从对象自身的名称空间中查找
  2. 再去子类的名称空间中查找
  3. 再从父类的名称空间中查找,最后从object中找,若没有会报错

python3中只有新式类,广度优先查找:继承多个父类时一直到继承object的类(根父类)不会从中找会回头找,第二个继承的父类。。。

python2中有经典类和新式类,深度优先查找:一直找到继承object的类(根父类)从中找不到才会找继承的第二个父类。。。

# 父类
class Foo:
    x = 10

#子类
class Goo(Foo):
    x = 20
    pass

obj_goo = Goo()
# 注意此处的x是通过对象来添加属性,是给对象添加属性,不是修改子类的属性
obj_goo.x = 30
print(obj_goo.x)

6、派生

指的是子类继承父类的属性与方法,并且派生出自己独有的属性与方法

若子类中的方法与父类的相同,优先用子类的

# 父类
class Foo:
    def f1(self):
        print('from Foof1...')
    def f2(self):
        print('from Foof2...')
        # 注意此处查找的f1应该先优先从子类找,最后从父类找
        self.f1()
        
# 子类
class Goo(Foo):
    def f1(self):
        print('from Goof1...')

goo_obj = Goo()
goo_obj.f2() 
# from Foof2...
# from Goof1...

7、子类继承父类并重用属性与方法

方式一:

​ 直接引用父类的__ init__(self)为其传参,并添加子类的属性

方式二:

​ 通过super来指向父类的属性,用super().init()为其传参添加子类的属性
super()是一个特殊类,调用super得到一个对象,该对象指向父类的名称空间

注意:使用哪一种方式都可以,但是不要混用

# 需求:学生有女朋友属性,老师有薪资属性
# 父类
class Foo:
    country = 'China'

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

# 子类
class Student(Foo):
    def __init__(self, name, age, sex, gril):
        # 方式一:直接引用父类的,需要传入self和其他参数
        Foo.__init__(self, name, age, sex)
        self.gril = gril

class Teacher(Foo):
    def __init__(self, name, age, sex, sal):
        # 方式二:对象本身当做self传入,不用super不要传入self,传入其他参数
        super().__init__(name, age, sex)
        self.sal = sal

stu_obj = Student('shen', 18, 'male', 'gril')
print(stu_obj.country, stu_obj.name, stu_obj.age, stu_obj.sex, stu_obj.gril)
# China shen 18 male gril
tea_obj = Teacher('wang', 24, 'female', 200000)
print(tea_obj.country, tea_obj.name, tea_obj.age, tea_obj.sex, tea_obj.sal)
# China wang 24 female 200000

8、经典类与新式类

新式类:

​ 1. 凡是继承了object的类或子孙类都是新式类

​ 2.在python3中所有的类都默认继承了object

经典类:

​ 1. 在python2中才会有经典类与新式类之分

​ 2.在python2中,凡是没有继承object的类,都是经典类

# python3中
class Foo: # 默认继承了object(Foo(object):)
    x = 1
    pass
class Goo(Foo):
    pass

print(Foo.__dict__)
print(Goo.__dict__)
# {'__module__': '__main__', 'x': 1, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None}
# {'__module__': '__main__', '__doc__': None}

9、mro继承序列

python3中提供了一个查找新式类查找顺序的内置方法,通过类调用mro()得到的返回结果是一个继承序列

super的继承顺序严格按照mro()继承序列,会基于当前位置按照mro序列顺序继续往后查找


class Foo1:
    def res(self):
        print('res from Foo1')
        # super会按照mro中序列基于当前位置继续往后查找
        super().res()

class Foo2:
    def res(self):
        print('res from Foo2')

class C(Foo1, Foo2):
    pass

obj_c = C()
print(C.mro()) # [<class '__main__.C'>, <class '__main__.Foo1'>, <class '__main__.Foo2'>, <class 'object'>]
obj_c.res()
#res from Foo1
# res from Foo2

10、钻石继承(菱形继承)

多继承情况下的菱形继承

mro的查找顺序:

​ 新式类:广度优先

​ 经典类:深度优先

新式类的广度优先:

# 新式类:
class A(object):
    def test(self):
        print('from A')
    pass
class B(A):
    # def test(self):
    #     print('from B')
    pass
class C(A):
    # def test(self):
    #     print('from C')
    pass
class D(B):
    # def test(self):
    #     print('from D')
    pass
class E(C):
    # def test(self):
    #     print('from E')
    pass
class F(D, E):
    # def test(self):
    #     print('from F')
    pass
# F-->D-->B-->E-->C-->A-->object
print(F.mro()) #[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
obj = F()
obj.test()

经典类的深度继承:

11、继承json模块,并派生出新功能

json模块正常无法存入类,转成json数据格式的,先如果需要存入一个类的数据则有两种方式

import json
from datetime import datetime

dic = {'time': datetime.now()}
print(type(datetime.now())) # <class 'datetime.datetime'>
# datetime.now()是一个类<class 'datetime.datetime'>正常无法转换存成json数据格式的
json.dumps(dic) # TypeError: Object of type datetime is not JSON serializable

方法一:将类转换成字符串存入

import json
from datetime import datetime

# 方法一:转换成字符串存入
dic = {'time': str(datetime.now())}
res = json.dumps(dic)
print(res) # {"time": "2019-11-27 14:38:01.079162"}

方法二:继承json模块派生出新功能来存取

import json
from datetime import datetime

# 方法二:继承json模块派生出新功能来存取
class MyJson(json.JSONEncoder):
    def default(self, o):
        # isinstance: 判断一个对象是否是一个类的实例
        if isinstance(o, datetime):
            return datetime.strftime(o, '%Y-%m-%d %X')
        else:
            return super().default(self, o)

dic = {'time': datetime.now()}
# cls=自定义的类
res = json.dumps(dic, cls=MyJson)
print(res) # {"time": "2019-11-27 14:38:01"}
posted @ 2019-11-26 18:56  Mr沈  阅读(270)  评论(0编辑  收藏  举报