一 继承

1、什么是继承
1)继承是一种创建新类的方式,新建的类可称为子类或派生类,父类又可称为基类或超类
子类会遗传父类的属性
2)需要注意的是:python支持多继承
在python中,新建的类可以继承一个或多个父类
class Parent1:
pass class Parent2:
pass class Sub1(Parent1): # 单继承
pass class Sub2(Parent1, Parent2): # 多继承
pass print(Sub1.__bases__)
print(Sub2.__bases__)
'''
__bases__用来查看继承哪些父类
(<class '__main__.Parent1'>,)
(<class '__main__.Parent1'>, <class '__main__.Parent2'>)
''' # PS:在python2中有经典类与新式类之分
# 新式类:继承了object类的子类,以及该子类的子类
# 经典:没有继承object类的子类,以及该子类的子类子子类 # PS2:在python3中没有继承任何类,那么会默认继承object类,所以python3中所有的类都是新式类
# print(Parent1.__bases__)
# print(Parent2.__bases__)
3)python的多继承
优点:子类可以同时遗传多个父类的属性,最大限度地重用代码
缺点:
1、违背人的思维习惯:继承表达的是一种什么“是”什么的关系
2、代码可读性会变差
3、不建议使用多继承,有可能会引发可恶的菱形问题,扩展性变差。
如果真的涉及到一个子类不可避免地要重用多个父类的属性,应该使用Mixins

2、为何要用继承:用来解决类与类之间代码冗余问题

3、如何实现继承
# 示范1:类与类之间存在冗余问题
class Student:
school = 'oldboy' def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex def choose_course(self):
print('{}正在选课'.format(self.name)) class Teather:
school = 'oldboy' def __init__(self, name, age, sex, salary, level):
self.name = name
self.age = age
self.sex = sex
self.salary = salary
self.level = level def score(self):
print('老师{}正在给学生打分'.format(self.name))
# 示范2:基于继承解决类与类之间的冗余问题
class OldboyPeople:
school = 'oldboy' def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex class Student(OldboyPeople): def choose_course(self):
print('{}正在选课'.format(self.name)) # stu_obj1 = Student('lq', 18, 'male')
# print(stu_obj1.__dict__)
# print(stu_obj1.school)
# stu_obj1.choose_course() class Teacher(OldboyPeople):
school = 'oldboy' def __init__(self, name, age, sex, salary, level):
# 老师的空对象,'ZD', 32, 'female', 4000, 10
OldboyPeople.__init__(self, name, age, sex)
self.salary = salary
self.level = level def score(self):
print('老师{}正在给学生打分'.format(self.name)) tea_obj = Teacher('ZD', 32, 'female', 4000, 10)
print(tea_obj.__dict__)

二 单继承下的属性查找

# 单继承背景下的属性查找
# 示范一
class Foo:
def f1(self):
print('Foo.f1') def f2(self):
print('FOO.f2')
self.f1() class Bar(Foo):
def f1(self):
print('Bar.f1') obj1 = Bar()
obj1.f2()
'''
对象的属性查找,先找自己对象的名称空间,在去类的名称空间找,再去父类名称空间找
FOO.f2
Bar.f1
'''
# 示范二(要调用Foo中的f1,可以用Foo类直接调f1):
class Foo:
def f1(self):
print('Foo.f1') def f2(self):
print('FOO.f2')
Foo.f1(self) # 调用当前类中的f1 class Bar(Foo):
def f1(self):
print('Bar.f1') obj2 = Bar()
obj2.f2()
'''
FOO.f2
Foo.f1
'''
# 示范三(隐藏属性的方法查找):
class Foo:
def __f1(self):
print('Foo.f1') def f2(self):
print('FOO.f2')
self.__f1() # 调用当前类中的f1 class Bar(Foo):
def f1(self):
print('Bar.f1') obj2 = Bar()
obj2.f2()
'''
FOO.f2
Foo.f1
'''

三 继承的实现原理

1、菱形问题介绍与mro
mro是c3算法实现的,python3可以调用.mro(),python2无法调用

class A(object):
def test(self):
print('from A') class B(A):
def test(self):
print('from B') class C(A):
def test(self):
print('from C') class D(B, C):
pass print(D.mro()) # 类D以及类D的对象访问属性都是参照该类的mro列表
# [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>] obj = D()
obj.test() # 结果为:from B print(C.mro()) # 类C以及类C的对象访问属性都是参照该类的mro列表
# [<class '__main__.C'>, <class '__main__.A'>, <class 'object'>] # 总结:类相关的属性查找(类名.属性,该类的对象.属性),都是参照该类的mro列表
2、深度优化和广度优化
2.1 如果多继承是非菱形继承,经典类与新式类的属性查找顺序一样:
都是一个分支一个分支地找下去,最后找object

class E:
def test(self):
print('from E') class F:
def test(self):
print('from F') class B(E):
def test(self):
print('from B') class C(F):
def test(self):
print('from C') class D:
def test(self):
print('from D') class A(B, C, D):
def test(self):
print('from A') print(A.mro())
'''
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class 'object'>]
''' obj = A()
obj.test() # 结果为:from B
# 可依次注释上述类中的方法test来进行验证
2.2 如果多继承是菱形继承,经典类与新式类的属性查找顺序不一样:
# 经典类:深度优先,会在检索第一条分支的时候就直接一条道走到黑,既会检索大脑袋(共同的父类G)
# 新式类:广度优先,会检索最后一条分支的时候检索大脑袋(G)

class G:
pass class E(G):
def test(self):
print('from E') class F(G):
def test(self):
print('from F') class B(E):
def test(self):
print('from B') class C(F):
def test(self):
print('from C') class D(G):
def test(self):
print('from D') class A(B, C, D):
def test(self):
print('from A') print(A.mro())
'''
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class '__main__.G'>, <class 'object'>]''' obj = A()
obj.test() # 结果为:from B
# 可依次注释上述类中的方法test来进行验证
# 经典类:也就是在python2中没有继承object,查找顺序是A-->B-->E-->G-->C-->F-->D
# 新式类:也就是python3和python2中继承了object,查找顺序是A-->B-->E-->C-->F-->D-->G # 总结:
# 多继承到底要不要用???
# 要用,但是规避几点问题
# 1、继承结构尽量不要过去复杂
# 2、要在多继承的背景下满足继承的什么“是”什么的关系---》mixins
3、子类派生的新方法如何重用父类的功能
# 方式一:指名道姓调用某一个类下的函数---》不依赖于继承关系
class OldboyPeople:
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex def f1(self):
print('{} say hello'.format(self.name)) class Teacher(OldboyPeople):
def __init__(self, name, age, sex, level, salary):
OldboyPeople.__init__(self, name, age, sex) # 调用的是函数,因而需要传入self
self.level = level
self.salary = salary tea_obj = Teacher('lq', 34, 'male', 10, 3000)
print(tea_obj.__dict__)
# {'name': 'lq', 'age': 34, 'sex': 'male', 'level': 10, 'salary': 3000} # 方式二:super()调用父类提供给自己的方法---》严格依赖继承关系
# 调用super()会得到一个特殊的对象,该对象会参照发起属性查找的那个类的mro,去当前类的父类(mro中的父类)中找属性
class OldboyPeople:
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex def f1(self):
print('{} say hello'.format(self.name)) class Teacher(OldboyPeople):
def __init__(self, name, age, sex, level, salary):
# super(Teacher,self).__init__(name,age,sex) # python2中super()的使用格式
super().__init__(name, age, sex) # 调用的是方法,自动传入对象
self.level = level
self.salary = salary print(Teacher.mro())
# [<class '__main__.Teacher'>, <class '__main__.OldboyPeople'>, <class 'object'>] tea_obj = Teacher('lq', 34, 'male', 10, 3000)
print(tea_obj.__dict__) # super()案例
# super()生成特殊对象,按照C类生成的mro顺序查找属性,B在A之后,需要去B中查找属性,结果为'from B'
class A:
def test(self):
super().test() class B:
def test(self):
print('from B') class C(A, B):
pass print(C.mro()) obj = C()
obj.test() # from B

四 组合

'''
在一个类中以另外一个类的对象作为数据属性,称为类的组合。
组合与继承都是用来解决代码的重用性问题。不同的是:继承
是一种“是”的关系,比如老师是人、学生是人,当类之间有很
多相同的之处,应该使用继承;而组合则是一种“有”的关系,
比如老师有生日,老师有多门课程,当类之间有显著不同,
并且较小的类是较大的类所需要的组件时,应该使用组合,如下示例
'''
class Course:
def __init__(self, name, period, price):
self.name = name
self.period = period
self.price = price def tell_info(self):
print(f'<{self.name} {self.period} {self.price}>') class Date:
def __init__(self, year, mon, day):
self.year = year
self.mon = mon
self.day = day def tell_birth(self):
print('<%s-%s-%s>' % (self.year, self.mon, self.day)) class People:
school = '清华大学' def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self.age = age # Teacher类基于继承来重用People的代码,基于组合来重用Date类和Course类的代码
class Teacher(People): # 老师是人
def __init__(self, name, sex, age, title, year, mon, day):
super().__init__(name, age, sex) # 重用父类的方法(继承)
self.birth = Date(year, mon, day) # 老师有生日,Date类的对象birth,作为了Teacher类的数据属性(组合)
self.courses = [] # 老师有课程,可以在实例化后,往该列表中添加Course类的对象,Course类的对象作为Teacher类的数据属性(组合) def teach(self):
print('%s is teaching' % self.name) python = Course('python', '3mons', 3000.0)
linux = Course('linux', '5mons', 5000.0)
teacher1 = Teacher('lili', 'female', 28, '博士生导师', 1990, 3, 23) # teacher1有两门课程
teacher1.courses.append(python)
teacher1.courses.append(linux) # 重用Date类的功能
teacher1.birth.tell_birth()
# <1990-3-23> # 重用Course类的功能
for obj in teacher1.courses:
obj.tell_info()
'''
<python 3mons 3000.0>
<linux 5mons 5000.0>
'''

 

python面向对象(继承)的更多相关文章

  1. python 面向对象 继承 派生 组合

    具体参考博客:http://www.cnblogs.com/linhaifeng/articles/6182264.html#_label12 一.面向对象 面向对象:对象与对象之间的相互交互,不可预 ...

  2. Python面向对象-继承和多态特性

    继承 在面向对象的程序设计中,当我们定义一个class时候,可以从现有的class继承,新的class成为子类,被继承的class称为基类,父类或超类. 比如,编写一个名为Animal的class: ...

  3. Python面向对象继承案例

    面向对象三大特性 封装 根据 职责 将 属性 和 方法 封装 到一个抽象的 类 中 继承 实现代码的重用,相同的代码不需要重复的编写 多态 不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活 ...

  4. Python 面向对象--继承,实现,依赖,关联,聚合,组合

    一. 继承 继承指的是子类继承父类除私有内容以外的其他所有内容, 并且子类具有增加自己新内容的能力. 举例说明: class Animal: print("吃是动物的本能") cl ...

  5. Python面向对象 -- 继承和多态、获取对象信息、实例属性和类属性

    继承和多态 继承的好处: 1,子类可以使用父类的全部功能 2,多态:当子类和父类都存在相同的方法时,子类的方法会覆盖父类的方法,即调用时会调用子类的方法.这就是继承的另一个好处:多态. 多态: 调用方 ...

  6. python面向对象 : 继承

    一. 初识继承 继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类. 当我们在定义多个类的时候,发现要用到相同的方法或变量,如 ...

  7. Python面向对象----继承, 重载

    1. 面向对象三大特性之继承. 继承的便捷是子类可以直接调用父类里面的方法和属性.(在强类型语言里面是只能调用公有成员), 不用重复的造轮子. 减少程序猿的负担.实现多态等上层结构 2. 父类代码 3 ...

  8. python 面向对象 继承

    什么是继承 继承表达的是一种”是“的关系,比如人是动物 继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类 继承是基于抽象的结 ...

  9. python面向对象继承

    class A(object):pass # 括号中可称为父类,基类,超类 class B:pass # 父类,基类,超类 class A_son(A,B):pass # 子类,派生类 class A ...

  10. 028.Python面向对象继承(单继承,多继承,super,菱形继承)

    一 继承的概念 种类 单继承 多继承 至少两个类: 子类:一个类继承另外一个类,那么该类是子类(也叫作衍生类) 父类:另外一个,这个被继承的类,叫做父类(也叫作超类),object 在python中 ...

随机推荐

  1. Linux 将命令的输出保存到文件

    当你在 Linux 终端中运行命令或脚本时,它会在终端中打印输出方便你立即查看.方法 1:使用重定向将命令输出保存到文件中你可以在 Linux 中使用重定向来达成目的.使用重定向操作符,它会将输出保存 ...

  2. [Ngbatis源码学习][SpringBoot] ApplicationContextInitializer接口类的使用和原理解读

    ApplicationContextInitializer接口类的使用和原理解读 在看Ngbatis源码的过程中,看到了自定义的ApplicationContextInitializer实现类,对Ap ...

  3. Nginx实战-公网LB限流配置等

    前提: Nginx要实现根据ip地址进行限流与不限流的区分需要通过源码包安装GeoIP模块 找到与yum安装版本相同的源码包,通过configure进行安装 ./configure --prefix= ...

  4. JS Leetcode 74. 搜索二维矩阵题解分析,二分法与坐标轴法

    壹 ❀ 引 本题来自Leetcode74. 搜索二维矩阵,虽然难度是中等,但如果站在做出来的角度,你会发现其实并不难,题目描述如下: 编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值. ...

  5. 如何查看Linux 内核是AMD、arm

    如何查看Ubuntu的内核是AMD.ARM.x86.x86_64 $ arch 注:x86_64,x64,AMD64基本上是同一个东西

  6. Js中的逻辑运算符

    Js中的逻辑运算符 JavaScript中有三个逻辑运算符,&&与.||或.!非,虽然他们被称为逻辑运算符,但这些运算符却可以被应用于任意类型的值而不仅仅是布尔值,他们的结果也同样可以 ...

  7. Windows 进程的一些学习笔记

    进程的内存映像是指内核在内存中如何存放可执行程序文件. 在将程序转化为进程的过程中,操作系统将可执行程序由硬盘复制到内存. 可执行程序和内存映像的区别 可执行程序位于磁盘中而内存映像位于内存中: 可执 ...

  8. Windows如何快速修改hosts文件

    作为开发人员,修改hosts文件可能是一个经常会执行的操作(使用自定义域名映射),但是如果每次都需要在Windows资源管理中进入到目录:C:\Windows\System32\drivers\etc ...

  9. crontab采坑总结

    目录 crontab环境变量 脚本缺少执行权限 crontab是Linux平台实现定时任务的服务工具,通常情况下该服务会预装在发行版中,直接使用即可. 关于crontab的详细用法参考:https:/ ...

  10. 硬件开发笔记(五): 硬件开发基本流程,制作一个USB转RS232的模块(四):创建CON连接器件封装并关联原理图元器件

    前言   有了原理图,可以设计硬件PCB,在设计PCB之间还有一个协同优先动作,就是映射封装,原理图库的元器件我们是自己设计的.为了更好的表述封装设计过程,本文描述了一个创建CON标准连接件封装,创建 ...