Python中的super()面向对象编程

目录
  • Python super()面向对象编程
    • 一、为什么要用 super()
    • 二、什么是 super
    • 三、继承中使用 super
      • 1、实例方法使用 super
      • 2、构造方法使用 super
    • 四、多继承中使用 super

Python super()面向对象编程

一、为什么要用 super()

当子类重写了父类方法时,又想调用父类的同名方法时,就需要用到 super()

二、什么是 super

  • 在 Python 中,super 是一个特殊的类
  • super() 就是使用 super 类创建出来的对象
  • 实际应用的场景:子类在重写父类方法时,调用父类方法

三、继承中使用 super

1、实例方法使用 super

类图

实际代码

class A:
    def __init__(self):
        self.n = 1

    def add(self, m):
        print(f'AAA [self] is {id(self)}')
        print(f'AAA [self.n] is {self.n}')
        self.n += m

class B(A):
    def __init__(self):
        self.n = 100

    # 重写父类方法
    def add(self, m):
        # 子类特有代码
        print(f'BBB [self] is {id(self)}')
        print(f'BBB [self.n] is {self.n}')

        # 调用父类方法
        super().add(m)

        self.n += m

b = B()
b.add(2)
print(b.n)

# 输出结果
BBB [self] is 4489158560
BBB [self.n] is 100

AAA [self] is 4489158560
AAA [self.n] is 100

104

super().add()  的确调用了父类方法
重点:此时父类方法的 self 并不是父类实例对象,而是子类实例对象

2、构造方法使用 super

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

    def prints(self):
        print("Animale name is ", self.name)

class Dog(Animal):
    def __init__(self, name, age):
        # 调用父类的 init 构造方法
        super(Dog, self).__init__(name)
        self.age = age

    def prints(self):
        # 调用父类的方法
        super(Dog, self).prints()
        print("Dog age is ", self.age)

dog = Dog("小汪", 10)
dog.prints()

# 输出结果
Animale name is  小汪
Dog age is  10

这里用了 super(子类名, self) ,和上面的 super() 是一样效果

调用父类方法有两种方式

  • super().父类方法()
  • super(子类名, self).父类方法()

其实还有第三种

在 Python  2.x 的时候,如果需要调用父类的方法,还可以用

父类名.方法(self)

  • 这种方式,Python 3.x 还是支持的
  • 过不不推荐,因为父类名发生变化的话,方法调用位置的类名也要同步修改

通过父类名调用父类方法(不推荐)

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

    def prints(self):
        print("Animale name is ", self.name)

class Dog(Animal):
    def __init__(self, name, age):
        # 调用父类的 init 构造方法
        Animal.__init__(self, name)
        self.age = age

    def prints(self):
        # 调用父类的方法
        Animal.prints(self)
        print("Dog age is ", self.age)

dog = Dog("小汪", 10)
dog.prints()

# 输出结果
Animale name is  小汪
Dog age is  10

通过父类名调用的这种方式,是需要传 self 参数的哦

温馨提示:
在开发时, 父类名.方法() super().方法() 两种方式不要混用哈

灵魂拷问一:既然已经重写了子类的构造方法,为什么还要去调用 super?
子类需要重写父类方法来实现子类独有的功能,但同时又需要依赖父类方法来完成某些逻辑

实际栗子

  • 在实现多线程的时候(后面会详细展开说多线程)
  • 父类 Thread 的构造方法包含了很多逻辑代码
  • 子线程虽然需要实现子类独有功能,但仍需父类方法来处理其他逻辑

from threading import Thread

class MyThread(Thread):
    def __init__(self, name):
        # 1、实现子类独有功能
        print("子类线程 %s" % name)
        # 2、需要依赖父类方法完成其他功能
        super().__init__(name=name)

四、多继承中使用 super

类图

实际代码

# 多继承
class Animal:
    def __init__(self, animalName):
        print(animalName, 'is an animal.')

# Mammal 继承 Animal
class Mammal(Animal):
    def __init__(self, mammalName):
        print(mammalName, 'is a mammal.')
        super().__init__(mammalName)

# CannotFly 继承 Mammal
class CannotFly(Mammal):
    def __init__(self, mammalThatCantFly):
        print(mammalThatCantFly, "cannot fly.")
        super().__init__(mammalThatCantFly)

# CannotSwim 继承 Mammal
class CannotSwim(Mammal):
    def __init__(self, mammalThatCantSwim):
        print(mammalThatCantSwim, "cannot swim.")
        super().__init__(mammalThatCantSwim)

# Cat 继承 CannotSwim 和 CannotFly
class Cat(CannotSwim, CannotFly):
    def __init__(self):
        print('I am a cat.');
        super().__init__('Cat')

# Driver code
cat = Cat()
print('')
bat = CannotSwim('Bat')

# 输出结果
I am a cat.
Cat cannot swim.
Cat cannot fly.
Cat is a mammal.
Cat is an animal.

Bat cannot swim.
Bat is a mammal.
Bat is an animal.

好像挺奇怪的,从输出结果看,为什么 CannotSwim 类里面的 super().__init__() 调用的是 CannotFly 类里面的方法呢?不是应该调用 CannotSwim 的父类 Mamal 的方法吗?

灵魂拷问二:super 的执行顺序到底是什么?

  • 其实 super() 并不一定调用父类的方法
  • super() 是根据类的 MRO 方法搜索顺序来决定调用谁的
  • super() 真正调用的是 MRO 中的下一个类,而不一定是父类
  • 当然,这种情况只会出现在多继承

先来看看 Cat 的 MRO

print(Cat.__mro__)

(<class '__main__.Cat'>, <class '__main__.CannotSwim'>, <class '__main__.CannotFly'>, <class '__main__.Mammal'>, <class '__main__.Animal'>, <class 'object'>)

从 Cat 的 MRO 可以看到

  • CannotSwim 后面跟的是 CannotFly 而不是 Mamal
  • 所以 CannotSwim 类里面的 super() 会调用 CannotFly 里面的方法

多继承的栗子二

实际代码

class A:
    def __init__(self):
        self.n = 2

    def add(self, m):
        # 第四步
        # 来自 D.add 中的 super
        # self == d, self.n == d.n == 5
        print('self is {0} @AAA.add'.format(self))
        self.n += m
        # d.n == 7

class C(A):
    def __init__(self):
        self.n = 4

    def add(self, m):
        # 第三步
        # 来自 B.add 中的 super
        # self == d, self.n == d.n == 5
        print('self is {0} @CCC.add'.format(self))
        # 等价于 suepr(C, self).add(m)
        # self 的 MRO 是 [D, B, C, A, object]
        # 从 C 之后的 [A, object] 中查找 add 方法
        super().add(m)

        # 第五步
        # d.n = 7
        self.n += 4
        # d.n = 11

class B(A):
    def __init__(self):
        self.n = 3

    def add(self, m):
        # 第二步
        # 来自 D.add 中的 super
        # self == d, self.n == d.n == 5
        print('self is {0} @BBB.add'.format(self))
        # self 的 MRO 是 [D, B, C, A, object]
        # 从 B 之后的 [C, A, object] 中查找 add 方法
        # 从 C 找 add 方法
        super().add(m)

        # 第六步
        # d.n = 11
        self.n += 3
        # d.n = 14

class D(B, C):
    def __init__(self):
        self.n = 5

    def add(self, m):
        # 第一步
        print('self is {0} @DDD.add'.format(self))
        # self 的 MRO 是 [D, B, C, A, object]
        # 从 D 之后的 [B, C, A, object] 中查找 add 方法
        # 从 B 找 add 方法
        super().add(m)

        # 第七步
        # d.n = 14
        self.n += 5
        # self.n = 19

d = D()
d.add(2)
print(d.n)

先看看 D 类的 MRO

print(D.__mro__)

(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

输出结果

self is <__main__.D object at 0x10c14a190> @DDD.add
self is <__main__.D object at 0x10c14a190> @BBB.add
self is <__main__.D object at 0x10c14a190> @CCC.add
self is <__main__.D object at 0x10c14a190> @AAA.add
19

调用顺序的确是 D、B、C、A

执行顺序

class D(B, C):          class B(A):            class C(A):             class A:
def add(self, m):       def add(self, m):      def add(self, m):       def add(self, m):
super().add(m)  1.--->  super().add(m) 2.--->  super().add(m)  3.--->  self.n += m
 self.n += 5   <------6. self.n += 3    <----5. self.n += 4     <----4. <--|
(14+5=19)               (11+3=14)              (7+4=11)                (5+2=7)

执行顺序图

到此这篇关于Python super()面向对象编程的文章就介绍到这了,更多相关Python super()内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 浅谈Python面向对象编程oop思想心得

    花了几个小时给小表弟普及了一下OOP的知识,索性总结一下写篇文章. OOP全称Object Oriented Programming 即面向对象编程,之所以有这么一个奇怪的称呼,是因为这个概念并非凭空而来,而是相对于"面向过程编程"的称呼. 而要了解什么是面向过程,就要从最早的即非面向对象,又非面向过程的原始编程说起. 上古时期 在最早的编程的上古时期,程序都只是简单地顺序执行: print("dosometing") a=int(input()) b=int(in

  • Python面向对象编程之类的概念

    目录 1.面向对象基本概念 1.1 万物皆对象 1.2 面向对象编程 1.3 面向对象的特征 2.Python面向对象的术语 3.Python类的构建 3.1 类的基本构建 3.2 类的构造函数 3.3 类的属性 3.4 类的方法 1.面向对象基本概念 1.1 万物皆对象 Python语言的中所有数据类型都是对象.函数是对象.模块是对象 Python所有类都是继承最基础的类object Python语言中的数据类型的操作功能都是类方法的体现 1.2 面向对象编程 面向对象编程又叫OOP(Obje

  • python读取ini配置的类封装代码实例

    这篇文章主要介绍了python读取ini配置的类封装代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 此为基础封装,未考虑过多异常处理 类 # coding:utf-8 import configparser import os class IniCfg(): def __init__(self): self.conf = configparser.ConfigParser() self.cfgpath = '' def checkSec

  • Python面向对象编程之类的封装

    目录 1.封装的理解 2.私有类属性.公开类属性.私有实例属性和公开实例属性 2.1 公开类属性 2.2 私有类属性 2.3 公开实例属性 2.4 私有实例属性 2.5 私有属性不一定真的私有 3.私有方法和公开方法 4.类的保留属性 5.类的保留方法 1.封装的理解 封装(Encapsulation):属性和方法的抽象 属性的抽象:对类的属性(变量)进行定义.隔离和保护 分为私有属性和公开属性: 私有属性:只能在类内部访问 公开属性:可以通过类.对象名访问 可以选择公开或隐藏属性,隐藏属性的内

  • Python attrs提高面向对象编程效率详细

    目录 1.attrs的使用 2.验证器 3.转换器 前言: Python是面向对象的语言,一般情况下使用面向对象编程会使得开发效率更高,软件质量更好,并且代码更易于扩展,可读性和可维护性也更高.但是如果在一个较大的项目中,如果实体类非常多并且有非常复杂的属性,你就会逐渐觉得Python的类写起来是真·"累".为什么这样说,看下下面这个Box类,属性有长(length).宽(width).高(hight): class Box: def __init__(self, length, wi

  • Python面向对象编程repr方法示例详解

    目录 为什么要讲 __repr__ 重写 __repr__ 方法 str() 和 repr() 的区别 为什么要讲 __repr__ 在 Python 中,直接 print 一个实例对象,默认是输出这个对象由哪个类创建的对象,以及在内存中的地址(十六进制表示) 假设在开发调试过程中,希望使用 print 实例对象时,输出自定义内容,就可以用 __repr__ 方法了 或者通过 repr() 调用对象也会返回 __repr__ 方法返回的值 是不是似曾相识....没错..和 __str__ 一样的

  • Python中的super()面向对象编程

    目录 Python super()面向对象编程 一.为什么要用 super() 二.什么是 super 三.继承中使用 super 1.实例方法使用 super 2.构造方法使用 super 四.多继承中使用 super Python super()面向对象编程 一.为什么要用 super() 当子类重写了父类方法时,又想调用父类的同名方法时,就需要用到 super() 二.什么是 super 在 Python 中,super 是一个特殊的类 super() 就是使用 super 类创建出来的对

  • python中什么是面向对象

    用面向对象的思维解决问题的重点 当遇到一个需求的时候不用自己去实现,如果自己一步步实现那就是面向过程:应该找一个专门做这个事的人来做. 面向对象(object-oriented ;简称: OO) 至今还没有统一的概念 我们可以把它定义为: 按人们 认识客观世界的系统思维方式,采用基于对象(实体) 的概念建立模型,模拟客观世界分析.设 计.实现软件的办法. 面向对象编程(Object Oriented Programming-OOP) 是一种解决软件复用的设计和编程方法. 这种方法把软件系统中相近

  • python中的super如何使用

    目录 技术背景 案例测试 结果分析 总结概要 版权声明 技术背景 python中的super,名为超类,可以简单的理解为执行父类的__init__函数.由于在python中不论是一对一的继承,还是一子类继承多个父类,都会涉及到执行的先后顺序的问题.那么本文就着重看下super的具体作用. 案例测试 通过设计这样一个案例,我们可以明确super的前后逻辑关系:先定义一个父类initial,在这个父类中有参数值param和函数func,然后用子类new来继承父类initial.继承之后,在子类的__

  • python 中的 super详解

    目录 super 的完整形式 super 的使用 提到 super,最直接的想法就是它代表了父类,替父类执行某些方法.但是理解也仅止步于此,下面对 super 做进一步理解 super 的完整形式 常见的 super 用法如下 class Person(): def __init__(self,name): self.name = name print('Person') class Male(Person): def __init__(self,age): super().__init__('

  • Python中的元类编程入门指引

    回顾面向对象编程 让我们先用 30 秒钟来回顾一下 OOP 到底是什么.在面向对象编程语言中,可以定义 类,它们的用途是将相关的数据和行为捆绑在一起.这些类可以继承其 父类的部分或全部性质,但也可以定义自己的属性(数据)或方法(行为).在定义类的过程结束时,类通常充当用来创建 实例(有时也简单地称为 对象)的模板.同一个类的不同实例通常有不同的数据,但"外表"都是一样 - 例如, Employee 对象 bob 和 jane 都有 .salary 和 .room_number ,但两者

  • Python中的super用法详解

    一.问题的发现与提出 在Python类的方法(method)中,要调用父类的某个方法,在Python 2.2以前,通常的写法如代码段1: 代码段1: 复制代码 代码如下: class A:   def __init__(self):    print "enter A"    print "leave A" class B(A):   def __init__(self):    print "enter B"    A.__init__(sel

  • Lua中函数与面向对象编程的基础知识整理

    函数 1. 基础知识 调用函数都需要写圆括号,即使没有参数,但有一种特殊例外:函数若只有一个参数且参数是字面字符串或table构造式,则圆括号可有可无,如dofile 'a.lua',f{x=10, y=20}. Lua为面向对象式的调用提供冒号操作符的特殊语法,如o.foo(o, x)等价于o:foo(x).和Javascript类似,调用函数时提供的实参数量可以与形参数量不同,若实参多了则舍弃,不足则多余的形参初始化为nil. 1.1 多重返回值 Lua允许函数返回多个结果,函数返回如ret

  • 介绍Python中的一些高级编程技巧

     正文: 本文展示一些高级的Python设计结构和它们的使用方法.在日常工作中,你可以根据需要选择合适的数据结构,例如对快速查找性的要求.对数据一致性的要求或是对索引的要求等,同时也可以将各种数据结构合适地结合在一起,从而生成具有逻辑性并易于理解的数据模型.Python的数据结构从句法上来看非常直观,并且提供了大量的可选操作.这篇指南尝试将大部分常用的数据结构知识放到一起,并且提供对其最佳用法的探讨. 推导式(Comprehensions) 如果你已经使用了很长时间的Python,那么你至少应该

  • Python中的super()方法使用简介

    子类里访问父类的同名属性,而又不想直接引用父类的名字,因为说不定什么时候会去修改它,所以数据还是只保留一份的好.其实呢,还有更好的理由不去直接引用父类的名字, 这时候就该super()登场啦-- class A: def m(self): print('A') class B(A): def m(self): print('B') super().m() B().m() 当然 Python 2 里super() 是一定要参数的,所以得这么写: class B(A): def m(self): p

  • 深入理解Python中的super()方法

    前言 python的类分别有新式类和经典类,都支持多继承.在类的继承中,如果你想要重写父类的方法而不是覆盖的父类方法,这个时候我们可以使用super()方法来实现 python语言与C++有相似的类继承,在类定义时,python中会自定义第一个self,类似C++中this指针,指向对象自身. python简单的类举例: >>> class hello(object): ... def print_c(): ... print"hello world!" >&g

随机推荐