python面向对象之继承

面向对象介绍

要理解面型对象,首先要理解对象这个概念,在程序中,我们将事物简化成数据(也就是属性和函数),事物的状态就是属性,动作就是函数

以一只猫为例,猫的属性可能有品种、毛色、年龄等等,这些都可以被描述成一个个属性,用变量表示,动作如吃饭、跑、抓等等可以用函数表示,将多有与猫相关的属性和函数整合到一起,就形成了猫这个对象

类和对象

上面我们知道了什么是对象的概念,但是现在有一个问题,对于猫来说,有很多种,长毛的短毛的,黑的白的,甚至名字都不一样,如果每一只猫我们都创建一个对象,在编写程序的时候就变得很麻烦,这就要说一下类的概念

什么是类呢,我们将所有的猫归为一个类,党要创建一对象时,直接在类中输入对象的参数(称为实例化)进行创建,这样简化了代码的重复性,提高了效率

很明显,在设计程序时,应该是先有类后有的对象

# 定义类
class BlackCat:  # 建议驼峰体进行命名
	color='black'
	def jump(self):
		print('它跳了一下')
blackcat1=BlackCat()  # 实例化过程,产生一个对象,队形有color属性和jump方法
# 这样类就创建好了,但是现在出案件的每只猫的颜色都是黑色,想要一些不同的属性,比如姓名,年龄怎么办
class BlackCat:  # 建议驼峰体进行命名
	color='black'
	def __init__(self,name,age):
		self.name=name
		self.age=age
	def jump(self):
		print('%s跳了一下'%self.name)
blackcat2=BlackCat('小白'2) 
# init方法是初始化操作,它能将实例化时的对象本身,和实例化时传入的参数传进去进行初始化,这样你可以的能够以多个不一样的对象
blackcat3=BlackCat('小黑'1) 

# 类和函数不一样,函数在定义的时候不会执行,只有加上括号的时候才会执行,但是类是在定义的时候就会进行加载,python中__dict__方法能够查看类中的定义的内容
print(BlackCat.__dict__)
# 返回一个字典,里面是属性和属性值,函数和函数对象组成的键值对
print(BlackCat.__dict__['color'])  # 当然也可以这样取值

# self的含义
'''
self并不是固定的,也就是说他只是一个变量名,就像args一样,是约定俗成的这个名字
self的含义是创建的对象的本身,blackcat3=BlackCat('小黑',1) 创建一个对象时,
self指代的就是blackcat3,init将对象本身传进去进行初始化,得到一个对象
'''

属性查找

在实例化一个对象的时候,会先创建一个对象的名称空间,将对象独有的属性(就是初始化时创建的属性)存放在里面,对于对象所共有的属性,存放在类的名称空间里面,进行查找时,先在对象的名称空间中进行查找,找不到再去类的名称空间中进行查找(也就是优先从对象本身的__dict__中查找,未找到,则去类的__dict__中查找)

新式类和经典类

在Python 3.x中取消了经典类,默认都是新式类,并且不必显式的继承object,也就是说:

class Person(object):
	pass
class Person():
	pass
# 二种写法并无区别,推荐第一种

但是在Python2.x中,默认都是经典类,只有显式继承了object才是新式类,即:

class Person(object):
	pass	# 新式类写法
class Person():
	pass	# 经典类写法

他们最明显的区别在于继承搜索的顺序发生了改变,即

  • 经典类多继承深度优先,先深入继承树左侧查找,然后再返回,开始查找右侧
  • 新式类多继承广度优先,先在水平方向查找,然后再向上查找

面向对象的三大特征*

继承、封装、多态

继承

之前我们了解了对象和类的关系,对象的一些属性实际上就是来自类的,实际上这就是一种继承关系,实际上类之间也存在继承关系,能够共用一些类属性

# 动物对象
class Animal:
	def __init__(self,name,age)
		self.name=name
		self.age=age
	def move(self):
		print('%s 动了一下'%self.name)

# 人实际上也是一种动物,在定义人的类的时候也有动物的属性和方法
# 为了提升效率,可以直接继承动物对象,但是人不同于动物可以思考
class Person(Animal):
	def think(self):
		print('%s 思考了一下'%self.name)

class Cat(Animal):
    pass

class Dog(Animal):
    pass

class BlackDog(Animal,Dog):
	pass

'''
就向上面的例子:
	Aminal:叫做父类,基类,超类
	Person、Cat、Dog:子类,派生类
**继承的分类**
单继承就是只继承一个类,前面的Person、Cat、Dog都是单继承
多继承就是集成多个类,如上面的BlackDog类

查看所有的父类:
__bases__方法:如Dog.__bases__
'''

继承的原理:菱形问题

菱形问题图示

'''
子类可以通过继承获得父类的非私有属性和非私有方法,不需要自己重新写
在多继承的情况下,就会出现复杂的继承关系
就会出现菱形继承:
	菱形继承也叫钻石继承(死亡钻石),在这种结构中,当D类的对象使用一个属性时,首先会在D类中查找是否有该属性和方法,如果没有则会到父类中查找,如果还没有则会继续往父类的父类中查找
'''

# 菱形继承问题详解:
class A():
    def __init__(self):
        print("进入A…")
        print("离开A…")

class B(A):
    def __init__(self):
        print("进入B…")
        A.__init__(self)  # 能够直接访父类的属性,这是其中的一种方式
        print("离开B…")
        
class C(A):
    def __init__(self):
        print("进入C…")
        A.__init__(self)
        print("离开C…")

class D(B, C):
    def __init__(self):
        print("进入D…")
        B.__init__(self)
        C.__init__(self)
        print("离开D…")

d = D()
'''
运行结果
进入D…
进入B…
进入A…
离开A…
离开B…
进入C…
进入A…
离开A…
离开C…
离开D…

上面的B类和C类都继承了A类,D类既继承了B类又继承了C类,这就形成了一个菱形的继承关系
在创建D类对象时,A类的__init__方法执行了两遍,也就是说在D向上执行了B执行了A,然后又向上执行了C又执行了A,这显然是不合理的,最简单的一个例子是,如果A类里面存在一个计数器,这时就被执行了两遍
'''
# 解决初始化问题:super
# super的用法在python3和python2中存在一些区别,在2中super(B, self).__init__(),在3中可以直接简写成super().__init__()

class A():
    def __init__(self):
        print("进入A…")
        print("离开A…")

class B(A):
    def __init__(self):
        print("进入B…")
        super(B,self).__init__()  # 能够直接访父类的属性,这是其中的一种方式
        print("离开B…")
        
class C(A):
    def __init__(self):
        print("进入C…")
        super(C,self).__init__()
        print("离开C…")

class D(B, C):
    def __init__(self):
        print("进入D…")
        super(D,self).__init__()
        print("离开D…")

d = D()
'''
运行结果
进入D…
进入C…
进入B…
进入A…
离开A…
离开B…
离开C…
离开D…

super方法的原理:
	为了解决python中多继承出现的重复继承的问题,python使用了C3算法生成了MRO列表(Method Resolution Order方法解析顺序),当出现多重继承问题时,C3算法会计算出一个继承顺序,super方法正是按照MRO列表中的顺序来进行寻找的
'''
# 如何查看继承顺序——MRO列表
print(D.__mro__)  # D这里指的是类名
# 需要注意的是,mro方法只能给类对象使用,实例对象不能使用

深度优先与广度优先

上面的例子可以看出,在多继承的情况下,如果一个类继承了两个类,就会出现两种情况,以上面的A、B、C、D为例,B的父类有两个选择,一个是深度优先先继承A,一个是广度优先先走C,最后走A,新式类都是广度优先,经典类都是深度优先

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值