#目录
  • 前言
  • 组合
  • 派生
    • 通过继承来覆盖重载方法
    • 最常用的重载场景实例方法的重载
    • 从标准类中派生类方法的重载

前言

我们定义一个类是希望能够把类当成模块来使用,并把类嵌入到我们的应用代码中,与其他的数据类型、逻辑执行流结合使用。一般来说我们可以使用两种方法在代码中利用类,那就是组合和派生。

组合

组合: 就是将不同的类混合并加入到其他类中,来 增加类的功能 / 提高代码的重用性 / 易于维护(对类的修改会直接反应到整个应用中) 。我们可以实例化一个更大的对象,同时还可以添加一些实例属性和实例方法的实现来丰富实例对象的功能。

In [1]: class NewAddrBookEntry(object):               # 定义一个类...:     """New address book entry class."""...:     def __init__(self, name, phone):          # 定义构造器...:         self.name = Name(name)                # 创建 Name 对象...:         self.phone = Phone(phone)             # 创建 Phone 对象...:         print "Created the instance for ", self.name

上述的 class NewAddrBookEntry 有它自身和其他类 Name/Phone 组合而成, 可以实现一些更为复杂的功能。

派生

当我们希望较小的类是较大的类的组件时,组合是一个很好的处理方式。但当我们希望 相同的类却具有一些不同的功能时 派生就是最好的处理方式。这也是面向对象编程最强大的功能之一 —— 使用一个已经定义好的类,扩展它的功能或者对其进行修改生成一个新的类,但却不会对原来的类造成影响。

子类会从基类继承他们的任何属性(数据和方法),这种派生是可以继承多代的,且可以同时继承多个基类。

语法

class SubClassName(ParentClass1[, ParentClass2, ...]):class_suite

EXAMPLE

In [8]: class Parent(object):...:    def __init__(self):...:        print "created an instance of: ", self.__class__.__name__...:...:In [9]: class Child(Parent):...:     pass...:In [10]: c = Child()
created an instance of:  ChildIn [14]: p = Parent()
created an instance of:  Parent

类 Child 的实例对象 c 并没有定义 __init__() 构造器,但仍然执行了 print 语句,这是因为 Child 从 Parent 继承了其构造器。

通过继承来覆盖(重载)方法

当我们派生一个子类,但同时希望相同的方法能在子类实现不同的功能,这时我们需要使用方法的 重载。使子类的方法能够覆盖父类的同名方法。

In [17]: class Parent(object):...:     def func(self):...:         print "This is Parent."...:In [18]: class Child(Parent):...:     def func(self):...:         print "This is Child."...:...:In [19]: p = Parent()In [20]: p.func()
This is Parent.In [21]: c = Child()In [22]: c.func()
This is Child.

这里子类 Child 重载了父类 Parent 的 func() 方法,实现了不同的功能。

但仍然有些场合需要我们即能使用子类的重载方法的同时,也要求我们重现父类方法的功能。那么我们可以调用那个被我们覆盖的父类方法吗?
答案是肯定的。

In [23]: Parent.func(c)
This is Parent.

我们可以通过 ParentClassName.functionName(object) 的方式来重现父类所被覆盖的方法。当然我们还有其他的方式可以实现这个效果,EG. 在子类的重载方法里显式的调用父类的同名方法:

In [24]: class Child(Parent):...:     def func(self):...:         print "This is Child."...:         Parent.func(self)In [25]: c = Child()In [26]: c.func()
This is Child.
This is Parent.

两种方式本质上是相同的,都是通过 父类名结合句点表达式 来实现对父类方法的调用,而且需要注意的是,在调用的时候必须传递一个实例对象给 func(),否则会触发参数不匹配的语法错误。

还有一个更好的实现方式就是子类使用 super() 内置函数:

In [27]: class Child(Parent):...:     def func(self):...:         print "This is Child."...:         super(Child, self).func()...:In [28]: c = Child()In [29]: c.func()
This is Child.
This is Parent.

super() 内置函数不仅能自动的找到父类方法,并且还是自动的为父类方法传入 self 参数来实现实例方法的绑定。

最常用的重载场景(实例方法的重载)

最常用的重载场景莫过于 重载父类的构造器 了。
在上述的例子可以看出,当我们在子类中没有重载构造器的时候,会自动的调用父类的构造器。这很明显是不符合我们的需求的,因为我们常常需要在子类中定义一些新的成员属性。但是问题是:当我们为了初始化子类中新的成员属性时,不可避免的需要重复的编写初始化从父类中继承而来的属性的代码。 这也不符合代码重用的原则,所以我们一般会采用 重载构造器(init()) + 重现父类构造器(super()) 的方式来解决这个问题。

In [32]: class Parent(object):...:     def __init__(self, name, age):...:         self.name = name...:         self.age = age...:         print "This is Parent."...:In [33]: class Child(Parent):...:     def __init__(self, name, age, sex):         # 初始化子类实例对象的属性...:         super(Child, self).__init__(name, age)  # 初始化父类实例对象的属性...:         self.sex = sex...:         print "This is Child."...:In [35]: p = Parent("fanguiju", "24")
This is Parent.In [36]: c = Child("fanguiju", "24", "man")
This is Parent.
This is Child.In [37]: c.name
Out[37]: 'fanguiju'In [38]: c.age
Out[38]: '24'In [39]: c.sex
Out[39]: 'man'

一般而言,我们会在子类的构造器中首先调用父类的构造器,当然这并不是强制的。只是为了我们能够在执行子类构造器的代码之前首先完成对父类属性的初始化,防止在调用从父类继承而来的属性时仍未初始化的问题出现。

使用 super() 内置函数的漂亮之处在于,我们不需要明确的给出父类的名字,交由解析器去自动的找到该子类的父类,并自动的传入 self 参数来完成绑定。这样能够让代码具有更高的灵活性,我们只需要改变子类的定义语句,就可以改变类的继承关系。

从标准类中派生(类方法的重载)

不可变数据类型的派生:定义一个精度为 2 的浮点数据类型
派生不可变标准类,经常需要重载类方法,而类方法的重载一般是重载 __new__(),也就是所谓的 真·构造器

class RoundFloat(float):def __new__(cls, value):return float.__new__(cls, round(value, 2))  # 将类对象 float 传入参数 clsIn [44]: RoundFloat(1.1111111)
Out[44]: 1.11

真·构造器会自动的将类对象 RoundFloat 传入 cls 参数,类似于构造器__init__(self)

可变数据类型的派生:定义一个有序的字典数据类型
可变数据类型的派生可能不需要使用 构造器 或者 真·构造器 也能够实现。

class SortedDict(dict):def keys(self):return sorted(super(SortedDict, self).keys())In [47]: for x in SortedDict((("name", "fanguiju"), ("age", 24), ("sex", "man"))):...:     print x...:
age
name
sex

通过 SortedDict 生成的字典按照字母的顺序排序。

需要注意的是: 在 Python 2.2 之后将类和类型合并了,所以所有的数据类型都是一个类,反之我们定义了一个类也相当于定义了一个新的类型。

Python 进阶_OOP 面向对象编程_组合与继承相关推荐

  1. Python 进阶_OOP 面向对象编程_类和继承

    目录 目录 类 最简单的类 类方法 构造器 __init__ 创建一个类 实例化一个对象 调用实例的方法和属性 创建子类 使用 super 来调用父类的构造器 实例化子类对象 调用子类的属性和方法 类 ...

  2. Python 进阶_OOP 面向对象编程_实例属性和方法

    目录 目录 构造器和解构器 构造器 __init__ 真构造器 __new__ 解构器 __del__ 实例方法 Python 中的 抽象方法 实例属性 查看实例属性 实例属性和类属性的区别 访问不可 ...

  3. Python 进阶_OOP 面向对象编程_类属性和方法

    目录 目录 类属性 调用类属性 查看类属性 特殊的类属性 类方法 真构造器 __new__ 类属性 在理解类属性之前要先搞清楚 实例属性 和 函数属性 之间的区别: 1. 实例属性:指的是实例化类对象 ...

  4. Python 进阶_OOP 面向对象编程_静态方法和类方法

    目录 目录 静态方法 类方法 使用函数修饰符来声明静态方法和类方法 静态方法 静态方法仅是类中的函数, 不需要绑定实例, 也就是说静态方法的定义不需要传入 self 参数. 静态方法不属于类的某一个实 ...

  5. Python 进阶_OOP 面向对象编程_self 的实例绑定

    目录 目录 self 和绑定 调用非绑定的方法 self 和绑定 在 Python 中 self 变量是特殊的, 其用于在实例方法中引用该方法所绑定的实例, 换句话说就是 Python 在实例化对象时 ...

  6. python进阶《面向对象编程》类和对象

    目录 零.前言 一.面向对象编程 (一)概念理解 二.类和对象的概念 (一)面向对象的两个重要概念类和对象. (二)类的解释   1.创建类   2.类属性(区别于下面的对象属性) (三)对象的解释 ...

  7. python完全支持面向对象编程_[Python] 类与面向对象编程

    1. class语句 类通常是由函数.变量和属性组成的集合.使用class语句可以定义类,例如: class Account(object): num_accounts = 0 def __init_ ...

  8. python进阶-面向对象编程四:包装授权和自定制列表某些方法

    包装和授权 # 包装和授权# 包装的过程:一个类型通常是对已存在的类型的一些定制, # 这种做法可以新建,修改或删除原有产品的功能,其它的则保持原样.# 授权是包装的一个特性. # 授权的过程:所有更 ...

  9. python采用面向对象编程模式吗_如何理解 Python 中的面向对象编程?

    现如今面向对象编程的使用非常广泛,本文我们就来探讨一下Python中的面向对象编程. 作者 | Radek Fabisiak 译者 | 弯月,责编 | 郭芮 以下为译文: Python支持多种类型的编 ...

最新文章

  1. 1-2、算法设计常用思想之贪婪法
  2. R语言处理非线性回归模型C-D方程,使用R语言进行多项式回归、非线性回归模型曲线拟合...
  3. 同事经常蹭我的车,我该怎么拒绝?
  4. 初学Python01
  5. Django 创建超级用户
  6. 杭电计算机2012年硕士研究生笔试详解
  7. Linux fcntl函数详解
  8. 输入框input或内容区域textarea中关于光标移动问题
  9. python画兔子代码_Python基础练习实例11(兔子问题)
  10. Mybatis-Plus批量新增
  11. java notifier_Java Notifier類代碼示例
  12. 以太网的网络电缆线被拔出怎么解决
  13. 关于文案排版的一些基本技巧
  14. Elasticsearch生命周期ILM若干时间后自动删除索引index
  15. win7 64位搭建scrapy
  16. 手机客户端的推广方式(iOS/Android应用推广)
  17. Android 7.0 新特性
  18. vb语言中怎样编码窗体中所有字体加粗_VBText控件中使字体加粗和倾斜的代码是什么...
  19. 图(graph)的基本知识
  20. week 14 限时模拟(猫睡觉问题)

热门文章

  1. 数据窗口动态生成列_Excel黑科技:教你8个简单实用的图表生成技巧
  2. c语言斐波那契数列_斐波那契数列之美
  3. 用友 服务器位置,用友的云服务器在哪里
  4. python判断文件夹是否存在
  5. 统计学习方法笔记(九)-最大熵原理及python实现
  6. 往年包场丘赛的北大,今年被清华逆袭了
  7. 刷题两个月,从入门到字节跳动offer,这是我的模板 | GitHub 1.2k星
  8. 马斯克在线“求逮捕”:美国县政府不让特斯拉复工,钢铁侠彻底怒了
  9. 谷歌重磅开源新技术:5行代码打造无限宽神经网络模型,帮助“打开ML黑匣子”...
  10. 百度Apollo升级发布15大新品,还要化身无人车基建狂魔 | 一文看尽首届Apollo生态大会...