继承

单继承

父类 基类
子类 派生类
继承:是面向对象软件技术当中的一个概念,如果一个类别A“继承自”另一个类别B,就把这个A称为“B的子类别”,而把B称为“A的父类别”也可以称“B是A的超类”。
继承可以使得子类别具有父类别的各种属性和方法,而不需要再次编写相同的代码。在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。另外,为子类别追加新的属性和方法也是常见的做法。 一般静态的面向对象编程语言,继承属于静态的,意即在子类别的行为在编译期就已经决定,无法在执行期扩充。
字面意思就是:子承父业,合法继承家产,就是如果你是独生子,而且你也很孝顺,不出意外,你会继承你父母所有家产,他们的所有财产都会由你使用(败家子儿除外)。
对象查找属性的顺序
对象空间--类空间 --父类空间
对象查找方法的顺序
对象空间--类空间 --父类空间
类查找属性和方法顺序
类空间--父类空间
示例1
若子类和父类有同一属性名,优先执行子类的,若子类没有再去父类找,若想同时调用子类和父类的属性,可以通过 类名. 或者super()来实现

既用了父类的属性,也同时调用了自己的属性

class Person(Animal):
    live = '有些人活着,其实....'
    def __init__(self,name,sex,age,mind):
        # Animal.__init__(self, name,sex,age) ##利用类名调用属性
        super().__init__(name,sex,age) #利用第super()来实现,就节省了self
        self.mind = mind
    def eat(self,):
        Animal.eat(self)
        print('人类也是需要吃饭的')

class Cat(Animal):
    def __init__(self,name,sex,age,clim):
        super().__init__(name,sex,age)
        self.clim = clim

class Dog(Animal):
    pass

p1 = Person('大黄', '男', 17,'有思想')
print(p1.__dict__)
打印结果:
{'name': '大黄', 'sex': '男', 'age': 17, 'mind': '有思想'}

既用了父类的方法,也同时调用了自己的方法

class Animal:
    live = '活着'
    def __init__(self,name,sex,age):
        self.name = name
        self.sex = sex
        self.age = age
    def eat(self):
        print('动物在吃饭')
class Person(Animal):
    live = '有些人活着,其实....'
    def eat(self):
        # Animal.eat(self) #直接使用类名来调用父类的方法
        super().eat() ##利用继承关系来实现
        print('人类也是需要吃饭的')
class Cat(Animal):
    pass
class Dog(Animal):
    pass
p1 = Person('大黄','男',17)
c1 = Cat('大橘','母',2)
p1.eat()
#当子类和父类方法名相同时
# 利用类名+方法的形式,可以在子类的方法中调用父类的方法,来实现既要用子类的功能,又要用父类的功能

多继承

子类不仅能有一个父类,还可以有多个父类,叫做多继承
它可以继承多个父类,并且可以使用所有父类的所有方法

class Shenxian:
    def fei(self):
        print('神仙会飞')
class Monkey:
    def chitao(self):
        print('猴子喜欢吃桃子')
class SunWuKong(Shenxian,Monkey):
    pass

obj = SunWuKong()
obj.chitao()
obj.fei()
打印结果:
猴子喜欢吃桃子
神仙会飞
多继承中很好理解,但是在多继承中, 存在着这样⼀个问题. 当两个⽗类中出现了重名⽅法的时候. 这时该怎么办呢? 这时就涉及到如何查找⽗类⽅法的这么⼀个问题.即MRO(method resolution order) 问题. 在python中这是⼀个很复杂的问题. 因为在不同的python版本中使⽤的是不同的算法来完成MRO的.
这里需要补充一下python中类的种类(继承需要):
在python2x版本中存在两种类.:
  ⼀个叫经典类. 在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写.
  ⼀个叫新式类. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。
python3x版本中只有一种类:
python3中使⽤的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object

经典类采用深度优先遍历方案

秉承着:从左至右,一条路走到头再返回的原则

新式类采用C3算法遍历原则,MRO序列

MRO就是一个有序列表
通用计算公式
mro(Child(Base1,Base2)) = [Child] + merge(mro(Base1),mro(Base2),[Base1,Base2])
其中:Child继承Base1和Base2
计算规则:
1.表头和表尾
表头:
列表的第一个元素是表头
表尾
列表中表头以外的元素集合就是表尾
2.列表之间的操作
[A] +[B] = [A,B]

如计算merge( [E,O], [C,E,F,O], [C] )
有三个列表 :  ①      ②          ③

1 merge不为空,取出第一个列表列表①的表头E,进行判断
   各个列表的表尾分别是[O], [E,F,O],E在这些表尾的集合中,因而跳过当前当前列表
2 取出列表②的表头C,进行判断
   C不在各个列表的集合中,因而将C拿出到merge外,并从所有表头删除
   merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] )
3 进行下一次新的merge操作 ......

拿这个图来举例

mro(A) = mro( A(B,C) )

原式= [A] + merge( mro(B),mro(C),[B,C] )

  mro(B) = mro( B(D,E) )
         = [B] + merge( mro(D), mro(E), [D,E] )  # 多继承
         = [B] + merge( [D,O] , [E,O] , [D,E] )  # 单继承mro(D(O))=[D,O]
         = [B,D] + merge( [O] , [E,O]  ,  [E] )  # 拿出并删除D
         = [B,D,E] + merge([O] ,  [O])
         = [B,D,E,O]

  mro(C) = mro( C(E,F) )
         = [C] + merge( mro(E), mro(F), [E,F] )
         = [C] + merge( [E,O] , [F,O] , [E,F] )
         = [C,E] + merge( [O] , [F,O]  ,  [F] )  # 跳过O,拿出并删除
         = [C,E,F] + merge([O] ,  [O])
         = [C,E,F,O]

原式= [A] + merge( [B,D,E,O], [C,E,F,O], [B,C])
    = [A,B] + merge( [D,E,O], [C,E,F,O],   [C])
    = [A,B,D] + merge( [E,O], [C,E,F,O],   [C])  # 跳过E
    = [A,B,D,C] + merge([E,O],  [E,F,O])
    = [A,B,D,C,E] + merge([O],    [F,O])  # 跳过O
    = [A,B,D,C,E,F] + merge([O],    [O])
    = [A,B,D,C,E,F,O]

super()的真正含义

class A:
    def func1(self):
        print('in A func1')
class B(A):
    def func1(self):
        super().func1()
        print('in B func1')
class C(A):
    def func1(self):
        print('in C func1')
class D(B,C):
    def func1(self):
        super().func1()
        #跳过本类,按照MRO的顺序执行下一类
        print('in D func1')
obj = D()
obj.func1() #D类的MRO顺序是:[D,B,C,A]
print(D.mro()) #查看该类的执行顺序
打印结果:
in C func1
in B func1
in D func1

多态

同⼀个对象, 多种形态. 这个在python中其实是很不容易说明⽩的. 因为我们⼀直在⽤. 只是没有具体的说. 比如. 我们创建⼀个变量a = 10 , 我们知道此时a是整数类型. 但是我们可以通过程序让a = "alex", 这时, a⼜变成了字符串类型. 这是我们都知道的. 但是, 我要告诉你的是. 这个就是多态性. 同⼀个变量a可以是多种形态。

封装

函数 模块 类 对象都属于封装
把很多数据封装到⼀个对象中. 把固定功能的代码封装到⼀个代码块, 函数, 对象, 打包成模块. 这都属于封装的思想. 具体的情况具体分析. 比如. 你写了⼀个很⽜B的函数. 那这个也可以被称为封装. 在⾯向对象思想中. 是把⼀些看似⽆关紧要的内容组合到⼀起统⼀进⾏存储和使⽤. 这就是封装. 

鸭子类型

看着像鸭子,就是鸭子
class A:
    def f1(self):
        print('in A f1')

    def f2(self):
        print('in A f2')

class B:
    def f1(self):
        print('in A f1')

    def f2(self):
        print('in A f2')

obj = A()
obj.f1()
obj.f2()

obj2 = B()
obj2.f1()
obj2.f2()
# A 和 B两个类完全没有耦合性,但是在某种意义上他们却统一了一个标准。
# 对相同的功能设定了相同的名字,这样方便开发,这两个方法就可以互成为鸭子类型。

# 这样的例子比比皆是:str  tuple list 都有 index方法,这就是统一了规范。
# str bytes 等等 这就是互称为鸭子类型。

类的约束

工作中如何对类进行约束,第一种方法,利用调用父类时的pay,就主动报错,raise,Python最常用的方式
class Payment:
    def pay(self, money):
        raise Exception('子类需要定义pay方法')

class Alipay(Payment):
    def pay(self, money):
        print('您用阿里支付了%s元' % money)

class QQpay(Payment):
    def pay(self, money):
        print('您用QQ支付了%s元' % money)

class Wechatpay(Payment):
    def zhifu(self, money):
        print('您用微信支付了%s元' % money)

obj = Wechatpay()
obj.pay(100)
打印结果:
    obj.pay(100)
  File "C:/Users/15471/PycharmProjects/newpro/day22/exercise.py", line 45, in pay
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
    raise Exception('子类需要定义pay方法')
Exception: 子类需要定义pay方法
# 方法二 抽象类 接口类 : 制定一个规范,强制子类必须有pay方法,如果没有,在你实例化的时候就会报错
from abc import ABCMeta,abstractmethod
class Payment(metaclass= ABCMeta):
    @abstractmethod
    def pay(self, money):
        pass

class Alipay(Payment):
    def pay(self, money):
        print('您用阿里支付了%s元' % money)

class QQpay(Payment):
    def pay(self, money):
        print('您用QQ支付了%s元' % money)

class Wechatpay(Payment):
    def zhifu(self, money):
        print('您用微信支付了%s元' % money)

obj = Wechatpay()
obj.pay(100)
打印结果:
报错
所以此时我们要用到对类的约束,对类的约束有两种:
1. 提取⽗类. 然后在⽗类中定义好⽅法. 在这个⽅法中什么都不⽤⼲. 就抛⼀个异常就可以了. 这样所有的⼦类都必须重写这个⽅法. 否则. 访问的时候就会报错. 
2. 使⽤元类来描述⽗类. 在元类中给出⼀个抽象⽅法. 这样⼦类就不得不给出抽象⽅法的具体实现. 也可以起到约束的效果.

python基础-面向对象的三大特征的更多相关文章

  1. python基础--面向对象基础(类与对象、对象之间的交互和组合、面向对象的命名空间、面向对象的三大特性等)

    python基础--面向对象 (1)面向过程VS面向对象 面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. ...

  2. Python 基础 面向对象之二 三大特性

    Python 基础 面向对象之二 三大特性 上一篇主要介绍了Python中,面向对象的类和对象的定义及实例的简单应用,本篇继续接着上篇来谈,在这一篇中我们重点要谈及的内容有:Python 类的成员.成 ...

  3. Python面向对象初始(三大特征,多态,继承,封装)

    Python面向对象的初始 面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优点是:极大的降低了写程序的 ...

  4. python基础——面向对象编程

    python基础——面向对象编程 面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的 ...

  5. python基础——面向对象的程序设计

    python基础--面向对象的程序设计 1 什么是面向对象的程序设计 面向过程的程序设计的核心是过程,过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优 ...

  6. Java面向对象的三大特征

    Java面向对象的三大特征 java面向对象的三大特征:“封装.继承.多态”.更多Java技术知识,请登陆疯狂软件教育官网.微信搜索微信号:疯狂软件,参加2015年优惠活动,有机会获得优惠劵和代金劵. ...

  7. C#学习笔记7:多态是面向对象的三大特征(封装、继承、多态)之一

    多态: 多态是面向对象的三大特征(封装.继承.多态)之一. 什么是多态? 一个对象表现出多种状态. 多态的实现方法: 1.虚方法: 2.抽象方法: 3.接口. PS:New 关键词可以隐藏父类的方法. ...

  8. OC面向对象的三大特征

    OC面向对象的三大特征 1.OC面向对象的三大特封装 1)封装:完整的说是成员变量的封装. 2)在成语方法里面的成员变量最好不要使用@public这样会直接暴露在外面被别人随随便便修改,封装的方法还可 ...

  9. 解析PHP面向对象的三大特征

    class BenHang extends Card{ /*构造函数与及构造的继承*/ function __construct($cardno,$pwd, $name,$money){ parent ...

随机推荐

  1. restful 风格 加上springmvc

    一.spring 版本:spring-framework-3.2.7.RELEASE 二.所需其它Jar包: 三.主要代码: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ...

  2. 洛谷-P3927 SAC E#1 - 一道中档题 Factorial

    原址 题目背景 数据已修改 SOL君(炉石主播)和SOL菌(完美信息教室讲师)是好朋友. 题目描述 SOL君很喜欢阶乘.而SOL菌很喜欢研究进制. 这一天,SOL君跟SOL菌炫技,随口算出了n的阶乘. ...

  3. .net的基础知识点

    在这个It市场都是风云变化的,都是又市场供需来定的,当年iOS火的一塌糊涂的,现在也出现找不到工作的,满地的出入门者,我就属于其中一个,在一个逼不得已的情况下,开始转行做.net ,我相信当年的很多. ...

  4. Java基础语法(自定义类、ArrayList集合)

    Java基础语法 今日内容介绍 u 自定义类 u ArrayList集合 第1章 引用数据类型(类) 1.1 引用数据类型分类 提到引用数据类型(类),其实我们对它并不陌生,如使用过的Scanner类 ...

  5. 2018年湘潭大学程序设计竞赛G又见斐波那契(矩阵快速幂)

    题意 题目链接 Sol 直接矩阵快速幂 推出来的矩阵应该长这样 \begin{equation*}\begin{bmatrix}1&1&1&1&1&1\\1 & ...

  6. 收集的20个非常有用的Java程序片段

    下面是20个非常有用的Java程序片段,希望能对你有用. 1. 字符串有整型的相互转换 String a = String.valueOf(2); //integer to numeric strin ...

  7. JFinal视频教程

    最近开始录制JFinal视频教程,发布在腾讯课堂上,免费公开面向JFinal开发者,作为JFinal开发者入门学习.实际项目用遇到问题寻找解决方案的最好途径. 目前JFinal课程已经开始更新. 腾讯 ...

  8. java面试题(杨晓峰)---第四讲强引用、软引用、弱引用、幻想引用有什么区别?

    在java语言中,除了原始数据类型的变量,其他所有都是所谓的引用类型,指向各种不同的对象,理解引用对于掌握java对象生命周期和JVM内部相关机制非常有帮助. 今天问题:强引用.软引用.弱引用.幻想引 ...

  9. 巧用代理设计模式(Proxy Design Pattern)改善前端图片加载体验

    这篇文章介绍一种使用代理设计模式(Proxy Design Pattern)的方法来改善您的前端应用里图片加载的体验. 假设我们的应用里需要显示一张尺寸很大的图片,位于远端服务器.我们用一些前端框架的 ...

  10. CF Gym 100187M Heaviside Function(二分)

    题意:给你一个函数和一些系数,给你一堆询问,求函数值. 根据s的符号,分成两组讨论,函数值与比x小的系数数量有关,二分输出答案. #include<cstdio> #include< ...