前沿

思考

问题一:两个中有大量重复的代码,是否能够只写一次 ?

问题二: 继承的意义是什么 ?

面向对象的编程带来的好处之一是代码的重用,实现这种重用方法之一是通过继承机制。

继承是两个类或多个类之间的父子关系,子类继承了基类的所有公有数据属性和方法,并且可以通过编写子类的代码扩充子类的功能。

开个玩笑地说,如果人类可以做到儿女继承了父母的所有才学并加以拓展,那么人类的发展至少是现在的数万倍。继承实现了数据属性和方法的重用,减少了代码的冗余度。

那么我们何时需要使用继承呢?如果我们需要的类中具有公共的成员,且具有一定的递进关系,那么就可以使用继承,且让结构最简单的类作为基类。一般来说,子类是父类的特殊化,如下面的关系:
哺乳类动物——>狗——>柯基

特定狗种类继承狗类,狗类继承哺乳动物类,狗类编写了描述所有狗种公有的行为的方法而特定狗种类则增加了该狗种特有的行为。

不过继承也有一定弊端,可能基类对于子类也有一定特殊的地方,如某种特定狗种不具有绝大部分狗种的行为,当程序员没有理清类间的关系时,可能使得子类具有了不该有的方法。
另外,如果继承链太长的话,任何一点小的变化都会引起一连串变化,我们使用的继承要注意控制继承链的规模。

继承

什么是继承?

继承就是让类和类之间转变为父子关系,子类可以直接访问(调用)父类的静态属性和方法。
在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类。

class 类1: #定义父类1pass
class 类2: #定义父类2pass
class SubClass1(类1):# 单继承,基类是ParentClass1,派生类是SubClasspass
class SubClass2(类1,类2):# python支持多继承,用逗号分隔开多个继承的类passprint(SubClass1.__bases__)  # 查看所有继承的父类
print(SubClass2.__bases__)
# ===============
# (<class '__main__.Father1'>,)
# (<class '__main__.Father1'>, <class '__main__.Father2'>)

继承的规则

1、子类继承父类的成员变量和成员方法
2、子类不继承父类的构造方法,能够继承父类的析构方法
3、子类不能删除父类的成员,但可以重定义父类成员
4、子类可以增加自己的成员

# python中子类继承父类成员变量之间的取值逻辑
class Person():def __init__(self, name, age, sex):self.name = "jasn"self.age = '18'self.sex = sexdef talk(self):print("i want to speak something to yo!!")class Chinese(Person):def __init__(self, name, age, sex, language):Person.__init__(self, name, age, sex)  # 用父类的name,age,sex 覆盖掉子类的属性#子类继承了父类 但是子类不想用父类的方法 我们可以直接覆盖掉self.age = age  # 覆盖掉了父类的age,取值为子类实例中传入age参数self.language = "chinese"def talk(self):print("我说的是普通话!!")Person.talk(self)obj = Chinese("nancy",'18','male',"普通话")
print(Chinese.__bases__)   #查看Chinese类的直接父类
print(obj.name)  # 对应场景A
print(obj.age)  # 对应场景B
print(obj.language)  # 对应场景C
obj.talk()  # 对应场景D# 总结:
# A:若父类中初始化了成员变量,子类调用父类构造方法未覆盖属性(self.name),则调用子类属性时取值为父类中初始化的成员变量;
# B:若父类中初始化了成员变量,若子类调用父类构造方法覆盖属性(self.age)则取值为子类实例中传入参数
# C:若父类未初始化该成员变量,则无论子类中有无进行对父类构造方法进行属性的覆盖,均取子类实例中传入的参数
# D:对于方法,如果子类有这个方法则直接调用,如果子类没有则去父类查找。父类没有则报错

执行结果:

(<class '__main__.Person'>,)
jasn
18
chinese
我说的是普通话!!
i want to speak something to yo!!

继承查找的方式跟变量的作用域类似,它会现在当前的类里找,找不到就向父类找,再找不到就再向上找,找不到就报错。

补充知识

issubclass(A,B),判断A类是否是B类的子类

isinstance(a,A),判断a是否是A类的实例对象;

类.__bases__ 查看类的直接父类

a.__mro__ 可以查看继承顺序

object类 是所有类的父类

调用父类方法:
第一种:super().方法() # 祖宗类
第二种:类名.方法(self)

super:调用父类( 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及很多的问题)

多继承

如果有多个基类,则需要全部都写在括号里,这种情况称为多继承。在Python中继承有以下一些特点:

  • 在继承中基类初始化方法_init_不会被自动调用。如果希望子类调用基类的_init方法,需要在子类的_init方法中显示调用了它。这与C++和C#区别很大。
  • 在调用基类的方法时,需要加上基类的类名前缀,且带上self参数变量。注意在类中调用该类中定义的方法时不需要self参数。
  • Python总是首先查找对应类的方法,如果在子类中没有对应的方法,Python才会在继承链的基类中按顺序查找。
  • 在Python继承中,子类不能访问基类的私有成员。

实例:

class Base:def play(self):print('我是你祖宗')class A(Base):def play(self):print("我是祖宗的儿子")class B(Base):def play(self):print('我是祖宗的女儿')class C(B,A):   # 谁先继承就用谁passc = C()
c.play()执行结果:
我是祖宗的女儿

__ new __

__ new __ (cls[,...])的参数,__ new __ 方法的第一个参数是这个类,而其余的参数会在调用成功后全部传递给 __ init __ 方法初始化。

所以, __ new __ 方法(第一个执行)先于 __ init __ 方法执行:

我们比较两个方法的参数,可以发现__new__方法是传入类(cls),而__init__方法传入类的实例化对象(self),而有意思的是,__ new __ 方法返回的值就是一个实例化对象(ps:如果__new__方法返回None,则__init__方法不会被执行,并且返回值只能调用父类中的__new__方法,而不能调用毫无关系的类的__new__方法)。

我们可以这么理解它们之间的关系,__new__是开辟疆域的大将军,而__init__是在这片疆域上辛勤劳作的小老百姓,只有__new__执行完后,开辟好疆域后,__init__才能工作。

实例:

class Base:def __init__(self):print('这是初始化方法里面')def __new__(cls, *args, **kwargs):print('这个cls是:',cls)  # cls 就是Base类print('这是在new方法里面')return object.__new__(cls)  # 必须有返回值
#实例的时候会先调用_new_方法,然后再调用初始化方法
test = Base()执行结果:
这个cls是: <class '__main__.Base'>
这是在new方法里面
这是初始化方法里面

绝大多数情况下,我们都不需要自己重写__new__方法,但在当继承一个不可变的类型(例如str类,int类等)时,它的特性就尤显重要了。我们举下面这个例子:

INIT

class CapStr(str):def __init__(self, string):self = string.upper()a = CapStr("I love China!")
print(a)执行结果:
I love China!

NEW

class CapStr(str):def __new__(cls, string):string = string.upper()return super().__new__(cls, string)a = CapStr("I love China!")
print(a)执行结果:
I LOVE CHINA!

我们可以根据上面的理论可以这样分析,我们知道字符串是不可改变的,所以第一个例子中,传入的字符串相当于已经被打下的疆域,而这块疆域除了将军其他谁也无法改变,__init__只能在这块领地上干瞪眼,此时这块疆域就是”I love China!“。而第二个例子中,__new__大将军重新去开辟了一块疆域,所以疆域上的内容也发生了变化,此时这块疆域变成了”I LOVE CHINA!“。

小结:__new____init__相互配合才是python中真正的类构造器。

单例模式(难点)

单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。

在 Python 中,我们可以用多种方法来实现单例模式:

方法一

class Person:pass
xiaoming = Person()
xiaohong = Person()
print(id(xiaoming))
print(id(xiaohong)) 地址是不是都是不一样的# 单例模式要实现的效果就是--- 每一次实例化所创建的实例都是同一个,内存地址都是一样的class A:_instance = None     # 实例def __new__(cls,*args, **kwargs):if cls._instance == None:cls._instance = object.__new__(cls)return cls._instanceelse:return cls._instancea = A()
b = A()
print(id(a))
print(id(b))执行结果:(仅参考)
2287413405568
2287413546736
2287413546960
2287413546960

方法二

class Person:def __new__(cls, *args, **kwargs):  # self 实例本身   cls 类本身if not hasattr(cls, 'instance'):cls.instance = super().__new__(cls)return cls.instancedef __init__(self, name):self.name = namexiaoming = Person('小明')
laowang = Person('老王')
print(id(xiaoming))
print(id(laowang))
print(laowang.name)
print(xiaoming.name)执行结果:
2096725684296
2096725684296
老王
老王

单例的运用:任务管理器 回收站 项目日志 多线程的线程池的设计一般也是采用单例模式

python学习笔记(八)——继承相关推荐

  1. Python学习笔记(八)

    Python基础总结 Python基础总结 Python简介 Python是一种解释型.面向对象.动态数据类型的高级程序设计语言.目前分为Python2.X和Python3.X两个版本,且Python ...

  2. 【懒懒的Python学习笔记八】

    面向对象编程是最有效的编程方法之一,在面向对象编程中,你编写表示现实世界中事物和情景的类,并基于这些类来创建对象.使用类来创建对象被称为实例化. 创建和使用类 使用类可以模拟任何东西.下面的实例编写一 ...

  3. Python学习笔记(八)爬虫基础(正则和编解码)

    知识点 正则 正则匹配url,引用re库,将需要匹配的字段用(.*?)来匹配,可以匹配任何字符串.如果有换行,可以用如下方式解决: 1. ([\s\S]*?) 2. re.findall(reg,ht ...

  4. python学习笔记八(集合)

    集合 set是一个无序的不重复元素序列. 用大括号或set()函数创建集合.注意:创建一个空集合用set(),不用{},{}用来创建空字典 basket = {'apple','orange','ap ...

  5. Python学习笔记总结

    了解了python语言后,决定以后使用python来进行各项工作,因此一直想要深入学习python.千里之行始于足下,万事开头难. 由于最近在准备写毕业论文,陆陆续续学习了Python的语法知识. P ...

  6. Python学习笔记(十九)面向对象 - 继承

    Python学习笔记(十九)面向对象 - 继承 一.继承的概念 # 继承:子类继承父类的所有方法和属性# 1. 子类 class A(object):def __init__(self):self.n ...

  7. python3.4学习笔记(八) Python第三方库安装与使用,包管理工具解惑

    python3.4学习笔记(八) Python第三方库安装与使用,包管理工具解惑 许多人在安装Python第三方库的时候, 经常会为一个问题困扰:到底应该下载什么格式的文件? 当我们点开下载页时, 一 ...

  8. python3第三方库手册_python3.4学习笔记(八) Python第三方库安装与使用,包管理工具解惑...

    python3.4学习笔记(八) Python第三方库安装与使用,包管理工具解惑 许多人在安装Python第三方库的时候, 经常会为一个问题困扰:到底应该下载什么格式的文件? 当我们点开下载页时, 一 ...

  9. 【免费分享编程笔记】Python学习笔记

    Python学习笔记~编程小哥令狐 文章目录 Python学习笔记~编程小哥令狐 一.Python运行发生情况 二.变量 2.1变量引入前说明 2.2变量的命名和使用 2.3字符串 2.3.1使用方法 ...

  10. 蒟蒻的python 学习笔记 ——北京理工大学嵩天mooc(有时间就看就更新,尽量让笔记容易懂,蟹蟹各位大神不吝赐教)

    蒟蒻的python 学习笔记 前言 课一:python语言程序设计 第一周:python 基本语法元素 1.1 程序设计基本方法 1.2 python 环境配置 1.3 实例1:温度转换 1.4 py ...

最新文章

  1. jquery的contains如何实现精准匹配
  2. matlab计算海洋浮力频率_水下机器人在海洋石油工程中的应用
  3. todolist实现删除的功能_coc-todolist: nvim/vim 的 todolist/task 管理插件
  4. C4.5中对于离散和连续特征的判定
  5. js中的事件循环和宏任务和微任务的理解
  6. POJ 3241Object Clustering曼哈顿距离最小生成树
  7. Linux的SOCKET编程 简单演示
  8. 大数据里的婚姻:婚后两年,出轨高峰……
  9. 如何安装python3.8.1_python3.8.1 安装
  10. 我是如何 2 个月拿到 4 份 Offer 并收入翻倍的?
  11. 吴恩达神经网络和深度学习-学习笔记-34-LeNet-5 + Alexnet + VGG
  12. php 清理脚本病毒,Autorun 病毒清除工具bat代码
  13. [行业报告] 芒果发布8月份国内移动广告平台数据报告
  14. 单词发音网页 (文本处理 python)
  15. python读取excel合并单元_python 读写excel (合并单元格)
  16. VS2013新建项目出现脚本错误的解决办法
  17. 时标网络图怎么画?详解两大画法
  18. 【BZOJ1061】【NOI2008】志愿者招募 费用流神题、单纯形裸题(代码费用流)
  19. 用Python搞出自己的云词图 | 【带你装起来】
  20. Golang四舍五入保留两位小数

热门文章

  1. 8. Leetcode 26. 删除有序数组中的重复项 (数组-同向双指针-快慢指针)
  2. 卷积神经网络补充—GoogleNet
  3. pytorch笔记:VGG 16
  4. python包介绍:numpy
  5. 文巾解题 77. 组合
  6. tableau可视化数据分析60讲(二)-tableau入门篇之各模块功能介绍
  7. tableau实战系列(八)-用数据桶实现图表的固定轴距
  8. python 系统进程_在Python中监视所有系统进程
  9. Ten ways to improve the performance of large tables in MySQL--转载
  10. 数字证书原理,公钥私钥加密原理