我的编程空间,编程开发者的网络收藏夹
学习永远不晚

python3--object类,继承与派生,super方法,钻石继承问题

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

python3--object类,继承与派生,super方法,钻石继承问题

昨天内容复习

组合:什么有什么的关系(例:老师有生日)

class Birthday:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

    def fmt(self):
        return '{}-{}-{}'.format(self.year, self.month, self.day)

class Teacher:
    def __init__(self, name, birth):
        self.name = name
        self.birthday = birth
    def birth_month(self):
        self.birthday.fmt()  # 引用组合对象的方法
        return self.birthday.month  # 引用组合对象的属性

birth = Birthday(1979, 10, 20)
sam = Teacher('Tom', birth)  # 将对象birth传进来作为实例化Teacher的属性
print(sam.birthday.year)  # 调用组合对象中的属性
print(sam.birthday.fmt())  # 调用组合对象中的方法

执行结果

1979

1979-10-20

总结:组合就是把一个对象,作为另外一个类的属性


继承

  属性:名字 性别,品种

  方法:吃 喝 爬树

  属性:名字 性别 品种

  方法:吃 喝 看门


class Animal:
    def __init__(self, name, sex, kind):
        self.name = name
        self.sex = sex
        self.kind = kind
    def eat(self):
        print('{} is eating'.format(self.name))
    def drink(self):
        print('{} is drinking'.format(self.name))

class Cat(Animal):
    def climb(self):
        print('{} is climbing'.format(self.name))

class Dog(Animal):
    def watch_door(self):
        print('{} is watching door'.format(self.name))

# 1 确认自己没有init方法
# 2 看看有没有父类
# 3 发现父类Animal有init
# 4 看着父类的init方法来传参数

tom = Cat('小黑', '公', '波斯猫')
sam = Dog('旺财', '公', '哈士奇')
print(Cat.__dict__)  # Cat.__dict__ Cat类的命名空间中的所有名字
print(tom.__dict__)  # tom.__dict__ 对象的命名空间中的所有名字
print(Dog.__dict__)  # Dog.__dict__ Dog类的命名空间中的所有名字
print(sam.__dict__)  # sam.__dict__ 对象的命名空间中的所有名字
tom.eat()
tom.climb()
sam.drink()
sam.watch_door()

执行结果

{'climb':

{'kind': '波斯猫', 'name': '小黑', 'sex': '公'}

{'__doc__': None, '__module__': '__main__', 'watch_door':

{'kind': '哈士奇', 'name': '旺财', 'sex': '公'}

小黑 is eating

小黑 is climbing

旺财 is drinking

旺财 is watching door


object类

class A:pass
a = A()
print(A.__bases__)

执行结果,可以看到A的父类为object,在python3中,只有新式类,默认继承object类

(


上面代码的执行步骤

1 创建了一个空的对象

2 调用init方法 -- class A里面没有写init方法,怎么不报错?执行了父类object的__init__方法

3 将初始化之后的对象返回调用出

在python3中所有的类都继承了object类

查看object的源码

blob.png

里面包含了__init__方法

object带双下划线的方法,有2个名字,比如双下方法,魔术方法

任何实例化都经历3步,如果类没有init,由object完成了


例1

class Animal:
    def __init__(self, name, hp, ad):
        self.name = name
        self.hp = hp
        self.ad = ad
    
    def eat(self):
        print('{}吃药回血了'.format(self.name))

class Person(Animal):
    def attack(self, dog):  # 派生方法
        print('{}攻击了{}'.format(self.name, dog.name))

class Dog(Animal):
    def bite(self, person):  # 派生方法
        print('{}咬了{}'.format(self.name, person.name))

sam = Person('Sam', 10, 20)  # 实例化一个对象sam,
dog = Dog('花花', 10, 5)     # 实例化一个对象dog
print(sam.__dict__)
print(dog.__dict__)

执行结果,打印对象属性

{'hp': 10, 'name': 'Sam', 'ad': 20}

{'hp': 10, 'name': '花花', 'ad': 5}


子类有的方法,叫派生方法


比如人有sex,狗有kind,现在需要在上面的例子中,给人额外加一个属性,狗额外加一个属性,那么首先想到的是在init里面加,如下


class Animal:
    def __init__(self, name, hp, ad):
        self.name = name
        self.hp = hp
        self.ad = ad

    def eat(self):
        print('{}吃药回血了'.format(self.name))

class Person(Animal):
    def __init__(self, sex):
        self.sex = sex
    def attack(self, dog):  # 派生方法
        print('{}攻击了{}'.format(self.name, dog.name))

class Dog(Animal):
    def __init__(self, kind):
        self.kind = kind
    def bite(self, person):  # 派生方法
        print('{}咬了{}'.format(self.name, person.name))



sam = Person('男')  # 实例化类Person,传一个参数性别
dog = Dog('哈士奇')  # 实例化类Dog,传一个参数品种
print(sam.__dict__)  # 打印对象sam的属性
print(dog.__dict__)  # 打印对象dog的属性

执行结果

{'sex': '男'}

{'kind': '哈士奇'}

why?为什么之前的属性都没有了,因为自己有了init后,它不会执行父类的init方法,那么如何执行父类的init呢?

有两种方法,第一种

class Animal:
    def __init__(self, name, hp, ad):
        self.name = name
        self.hp = hp
        self.ad = ad

    def eat(self):
        print('{}吃药回血了'.format(self.name))

class Person(Animal):
    def __init__(self, name, hp, ad, sex):
        Animal.__init__(self, name, hp, ad)
        self.sex = sex
    def attack(self, dog):  # 派生方法
        print('{}攻击了{}'.format(self.name, dog.name))

class Dog(Animal):
    def __init__(self, name, hp, ad, kind):
        Animal.__init__(self, name, hp, ad)
        self.kind = kind
    def bite(self, person):  # 派生方法
        print('{}咬了{}'.format(self.name, person.name))

sam = Person('Sam', 10, 20, '男')
dog = Dog('花花', 10, 5, '哈士奇')
print(sam.__dict__)
print(dog.__dict__)

执行结果

{'ad': 20, 'name': 'Sam', 'sex': '男', 'hp': 10}

{'kind': '哈士奇', 'ad': 5, 'name': '花花', 'hp': 10}


可以看到,父类的属性也继承了,自己添加的属性也有,怎么实现的?

当执行init之前,开辟内存空间,self执行的是同一块内存空间,sam里面的self,指向都是一样的,在同一个类里面,self指向的都是同一个,如下图

blob.png


第二种写法

class Animal:
    def __init__(self, name, hp, ad):
        self.name = name
        self.hp = hp
        self.ad = ad

    def eat(self):
        print('{}吃药回血了'.format(self.name))

class Person(Animal):
    def __init__(self, name, hp, ad, sex):
        super().__init__(name, hp, ad)
        self.sex = sex
    def attack(self, dog):  # 派生方法
        print('{}攻击了{}'.format(self.name, dog.name))

class Dog(Animal):
    def __init__(self, name, hp, ad, kind):
        super().__init__(name, hp, ad)
        self.kind = kind
    def bite(self, person):  # 派生方法
        print('{}咬了{}'.format(self.name, person.name))
sam = Person('Sam', 10, 20, '男')
dog = Dog('花花', 10, 5, '哈士奇')
print(sam.__dict__)
print(dog.__dict__)

执行结果

{'name': 'Sam', 'hp': 10, 'sex': '男', 'ad': 20}

{'name': '花花', 'hp': 10, 'kind': '哈士奇', 'ad': 5}

在单继承中,super负责找到当前类(也就是Person和Dog的父类Animal)所在的父类,在这个时候不需要再手动传self


修改上面例子,增加新的需求:人吃药要钱,狗吃药不要钱

class Animal:
    def __init__(self, name, hp, ad):
        self.name = name
        self.hp = hp
        self.ad = ad

    def eat(self):
        print('eating in Animal')
        self.hp += 20

class Person(Animal):
    def __init__(self, name, hp, ad, sex):
        super().__init__(name, hp, ad)
        self.sex = sex
        self.money = 100  # 设置初始钱为100
    def attack(self, dog):  # 派生方法
        print('{}攻击了{}'.format(self.name, dog.name))

    def eat(self):
        super().eat()  # super()方法找到父类,父类点eat(),执行父类里面的eat()方法
        print('eating in Person')
        self.money -= 50

class Dog(Animal):
    def __init__(self, name, hp, ad, kind):
        super().__init__(name, hp, ad)
        self.kind = kind
    def bite(self, person):  # 派生方法
        print('{}咬了{}'.format(self.name, person.name))
sam = Person('Sam', 10, 20, '男')
dog = Dog('花花', 10, 5, '哈士奇')
sam.eat()
print(sam.__dict__)
print(dog.__dict__)

执行结果

eating in Animal

eating in Person

{'sex': '男', 'ad': 20, 'money': 50, 'name': 'Sam', 'hp': 30}

{'ad': 5, 'kind': '哈士奇', 'name': '花花', 'hp': 10}


继承

父类是新式类,那么继承的子类全部都是新式类,python3里面没有经典类

单继承 新式类

blob.png


多继承 新式类(也叫钻石继承)

blob.png


例子

class A:
    def func(self):
        print('A')
class B(A):
    def func(self):
        print('B')
class C(A):
    def func(self):
        print('C')
class D(B,C):
    def func(self):
        print('D')
d = D()
d.func()

执行结果,why?

D

blob.png

龟壳模型

blob.png



新式类 多继承 寻找名字的顺序 遵循广度优先


super在多继承中,是找下一个节点的,而不是找父类的!

blob.png


总结,在python3中都是新式类,使用的是广度优先原则

super()

在单继承中就是单纯的寻找父类

在多继承中就是根据子节点所在图的mro顺序寻找下一个类

例子

class A:
    def func(self):
        print('A')
class B(A):
    def func(self):
        print('B')
class C(A):
    def func(self):
        print('C')
class D(B):
    def func(self):
        print('D')
class E(C):
    def func(self):
        print('E')
class F(D,E):
    def func(self):
        print('F')
st = F()
print(F.mro())

使用F.mro()打印出寻找类的顺序

[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]


在python2.x中,经典类多继承使用深度优先原则

在python2.x中,不手动继承object类,都属于经典类


blob.png

深度优先,一条路走到底,找不到就会回来找其他的


blob.png


经典类:在python2.x版本才存在,且必须不继承object

遍历的时候遵循深度优先算法

没有mro方法

没有super()方法


新式类:在python2.x版本中,需要继承object,才是新式类

遍历的时候遵循广度优先算法

在新式类中,有mro方法

有super()方法,但是在2.x版本的解释器中,必须传参数(子类名,子类对象)

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

python3--object类,继承与派生,super方法,钻石继承问题

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

python3--object类,继承与派生,super方法,钻石继承问题

昨天内容复习组合:什么有什么的关系(例:老师有生日)classBirthday:def__init__(self,year,month,day):self.year=yearself.month=monthself.day=daydeffm
2023-01-30

C++ 成员函数详解:对象方法的虚继承与钻石问题

虚继承解决了多重继承中的“钻石问题”,其中一个类从两个或多个具有相同基类的子类继承时。通过在派生类的继承规范中使用 virtual 关键字,派生类不会获得基类的副本,而是通过指针间接访问基类的方法。这样,派生类只获得一个来自最终从基类派生的
C++ 成员函数详解:对象方法的虚继承与钻石问题
2024-04-29

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录