漫天飞雪

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

"""
一、继承
  继承是一种创建新类的方式,新建的类可以继承一个或多个父类(python支持多继承),父类又可称为基类
或超类,新建的类称为派生类或子类。
子类会“”遗传”父类的属性,从而解决代码重用问题
python中类的继承分为:单继承和多继承
经典类与新式类
# 创建父类
# class father1:
  # pass
# class father2:
  # pass
# class chirl1(father1):
  # pass
# class chirl2(father1,father2):
  # pass
1.只有在python2中才分新式类和经典类,python3中统一都是新式类
2.在python2中,没有显式的继承object类的类,以及该类的子类,都是经典类
3.在python2中,显式地声明继承object的类,以及该类的子类,都是新式类
3.在python3中,无论是否继承object,都默认继承object,即python3中所有类均为新式类

# 查看继承使用‘.__bases__’方法
# print(chirl1.__bases__)#(<class '__main__.father1'>,)
# print(chirl2.__bases__)#(<class '__main__.father1'>, <class '__main__.father2'>)

提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,
它提供了一些常见方法(如__str__)的实现。
# 查看下父类的‘.__bases__’
# print(father1.__bases__)#(<class 'object'>,)
# print(father2.__bases__)#(<class 'object'>,)
二、继承与抽象
  抽象的意思,是子类中寻找继承父类的相似的特征部分,抽象即抽取类似或者说比较像的部分。
  继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式
去表达出抽象的结构。

#继承的代码实现
实例1
# class Animal:
#
  # def eat(self):
    # print("%s 吃 " %self.name)
#
  # def drink(self):
    # print ("%s 喝 " %self.name)
#
    # def shit(self):
      # print ("%s 拉 " %self.name)
#
    # def pee(self):
      # print ("%s 撒 " %self.name)
#
#
# class Cat(Animal):
#
  # def __init__(self, name):
    # self.name = name
    # self.breed = '猫'
#
  # def cry(self):
    # print('喵喵叫')
#
# class Dog(Animal):
#
  # def __init__(self, name):
    # self.name = name
    # self.breed='狗'
#
  # def cry(self):
    # print('汪汪叫')
#
# cat1=Cat('cat_one')
# cat1.eat()
# cat1.drink()
# cat1.shit()
# cat1.pee()
# print("------------------")
# dog1=Dog('dog_one')
# dog1.pee()
# dog1.shit()
# dog1.drink()
# dog1.eat()
# print("------------------")
# dog2=Dog('dog_two')
# dog2.pee()
# dog2.shit()
# dog2.drink()
# dog2.eat()
# 输出结果
# cat_one 吃
# cat_one 喝
# cat_one 拉
# cat_one 撒
# ------------------
# dog_one 撒
# dog_one 拉
# dog_one 喝
# dog_one 吃
# ------------------
# dog_two 撒
# dog_two 拉
# dog_two 喝
# dog_two 吃
# 实例2
class Hero:
  def __init__(self,nickname,aggressivity,life):
    self.nickname=nickname
    self.agressivity=aggressivity
    self.life=life
  def move_forward(self):
    print('%s move forword '%self.nickname)
  def move_backward(self):
    print('%s move backword'%self.nickname)
  def move_right(self):
    print("%s move right"%self.nickname)
  def move_left(self):
    print("%s move left")%self.nickname
  def attack(self,enemy):
    enemy.life-=self.agressivity
#继承父类Hero
class Garen(Hero):
  pass
class Riven(Hero):
  pass

garen=Garen('盖伦大保健来也',150,400)
riven=Riven('瑞文小标砸',130,450)
print(garen.life)
riven.attack(garen)
print(garen.life)
# 输出结果:
# 400
# 270
提示:用已经有的类建立一个新的类,这样就重用了已经有的软件中的一部分设置大部分,大大生了编程工作量,这就是常说的软件重用,不仅可以重用自己的类,
也可以继承别人的,比如标准库,来定制新的数据类型,这样就是大大缩短了软件开发周期,对大型软件开发来说,意义重大.

注意:像g1.life_value之类的属性引用,会先从实例中找life_value然后去类中找,然后再去父类中找...直到最顶级的父类。

三、属性查找和继承的顺序
1)属性的查找
单继承:在单继承背景下属性的查找优先级:对象->对象的类->父类->父类.....
class father:
  def f1(self):
    print('father>>>f1')
  def f2(self):
    print('father>>>f2')
  self.f1()
class chirl(father):
  def f1(self):
    print('chirl>>>f1')
chirl01=chirl()
chirl01.f1()
# 输出结果
# chirl>>>f1
# chirl01.f2()
# 输出结果
# father>>>f2
# chirl>>>f1

多继承:
# 新式类 : 广度优先查找,从左往右一个分支一个分支的查找,在最后一个分支才去查找顶级类
# 经典类 : 深度优先查找,从左往右一个分支一个分支的查找,在第一个分支就查找顶级类

# 第四层:
class G(object):
  # x = 'G'
  pass

# 第三层
class E(G):
  # x = 'E'
  pass

class F(G):
  # x = 'F'
  pass

# 第二层
class B(E):
  # x = 'B'
  pass

class C(F):
  # x = 'C'
  pass

class D(G):
  # x = 'D'
  pass

# 第一层
class A(B, C, D):
  # x = 'A'
  pass

obj=A()
# obj.x=111
print(obj.x)
#新式类(广度优先): obj->A->B->E->C-F->D->G->object
#经典类(深度优先): obj->A->B->E->G->C-F->D

# python专门为新式类内置了一个mro的方法,用来查看c3算法的计算结果,结果是??
print(A.mro())

2)继承的顺序(MRO列表)
继承原理(python如何实现的继承)

python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,
这个MRO列表就是一个简单的所有基类的线性顺序列表,
例如
>>> F.mro() #等同于F.__mro__
[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
而这个MRO列表的构造是通过一个C3线性化算法来实现的。

并所有父类的MRO列表并遵循如下三条准则:
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类

四、派生,子类除了继承父类的属性,也可以自己拥有自己特有的属性,需要强调的是:如果重新定义了自己本身拥有的属性
,在调用属性时,是以自己的属性为准的哦
案例:
还是以为英雄属性为基础,上面已经在继承的例子中展示了子类继承父类的英雄属性,同时也是可以在自己的子类里定义
父类里已有的属性,但是如果后期调用则是以自己拥有的为准

class Hero:
  def __init__(self, nickname, aggressivity, life):
    self.nickname = nickname
    self.agressivity = aggressivity
    self.life = life
  def attack(self,enemy):
    print("from hero")
    enemy.life-=self.agressivity

#子类继承父类,把attack属性新增到自己类下
class Riven(Hero):
  camp='Noxus'

  def attack(self,enemy):
    print("from riven")
    enemy.life -= self.agressivity

class Garen(Hero):
  camp='Decima'

  def attck(self,enemy):
    print("from garen")
    enemy.life -= self.agressivity

garen=Garen('garen',125,460)
riven=Riven("riven",130,450)
print(garen.life)
riven.attack(garen)
print(garen.life)
# 输出结果
# 460
# from riven
# 330

五、组合和重用性
# 组合
# 软件重用的重要方式除了继承之外还有另外一种方式,即:组合
# 组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合
class Hero:
  def __init__(self, nickname, aggressivity, life,money):
    self.nickname = nickname
    self.aggressivity = aggressivity
    self.life = life
    self.money=money
  def attack(self, enemy):
    print("from hero")
    enemy.life -= self.agressivity
# 武器装备
class dolan:
  def __init__(self,price,life,aggressivity):
  self.price=price
  self.life=life
  self.aggressivity=aggressivity
  def update(self,obj):
    obj.life+=self.life
    obj.money-=self.price
    obj.aggressivity += self.aggressivity
# 英雄属性,目前是继承了hero的父类
class Riven(Hero):
  camp = 'Noxus'
  def attack(self, enemy):
  print("from riven")
  enemy.life -= self.agressivity

class Garen(Hero):
  camp = 'Decima'
  def attck(self, enemy):
    print("from garen")
    enemy.life -= self.agressivity

garen=Garen('garen',125,460,1000)
riven=Riven("riven",130,450,1200)
dolan_equip=dolan(450,80,20)
print(dolan_equip.__dict__)
print(riven.__dict__)
print(garen.__dict__)

if garen.money>dolan_equip.price:
# garen.dolan_equip=dolan_equip
  dolan_equip.update(garen) #obj
  dolan_equip.update(riven) #obj

  print(garen.__dict__)
  print(riven.__dict__)

# garen.dolan_equip=dolan_equip加组合后输出结果
# {'price': 450, 'life': 80, 'aggressivity': 20}
# {'nickname': 'riven', 'aggressivity': 130, 'life': 450, 'money': 1200}
# {'nickname': 'garen', 'aggressivity': 125, 'life': 460, 'money': 1000}
# {'nickname': 'garen', 'aggressivity': 145, 'life': 540, 'money': 550, 'dolan_equip': <__main__.dolan object at 0x03547470>}
# {'nickname': 'riven', 'aggressivity': 150, 'life': 530, 'money': 750}
# garen.dolan_equip=dolan_equip没有加组合后输出结果
# {'price': 450, 'life': 80, 'aggressivity': 20}
# {'nickname': 'riven', 'aggressivity': 130, 'life': 450, 'money': 1200}
# {'nickname': 'garen', 'aggressivity': 125, 'life': 460, 'money': 1000}
# {'nickname': 'garen', 'aggressivity': 145, 'life': 540, 'money': 550}
# {'nickname': 'riven', 'aggressivity': 150, 'life': 530, 'money': 750}
# 区别是在garen的英雄属性装备后面少了一个装备属性,没法辨别是否购买过什么装备进行加持属性 'dolan_equip': <__main__.dolan object at 0x03547470>

六、子类调用父类的方法
方法一:指名道姓,即父类名.父类方法()
# 在子类派生出的新方法中重用父类功能的方式一:
# 指名道姓地引用某一个类中的函数
# 总结:
# 1. 与继承无关
# 2. 访问是类的函数,没有自动传值的效果
class Common:
  def __init__(self,name,age,sex):
    self.name=name
    self.age=age
    self.sex=sex
#课程,需要手动添加现在存在的课程
class Course:
  def __init__(self,name,period,price):
    self.name=name
    self.period=period
    self.price=price
  def course_info(self):
    print('%s-%s-%s'%(self.name,self.period,self.price))
#教师
class Teacher(Common):
  def __init__(self,name,age,sex,job_title):
    Common.__init__(self,name,age,sex)
      self.job_title=job_title
      self.course=[]
      self.students=[]
#学生
class Student(Common):
  def __init__(self,name,age,sex):
    Common.__init__(self,name,age,sex)
      self.course=[]

joke_teacher=Teacher('joke',18,'male','gold')
zl_student=Student('zl',16,'female')
python=Course('python','3months',3000)
linux=Course('linux','4months',4000)

print(joke_teacher.__dict__)
print(zl_student.__dict__)
Course.course_info(python)
Course.course_info(linux)

#添加课程
joke_teacher.course.append(python)
joke_teacher.course.append(linux)
zl_student.course.append(python)

#为老师添加学生
joke_teacher.students.append(zl_student)
方法2:super()
# 在子类派生出的新方法中重用父类功能的方式二:super()必须在类中用
# 在python2中:super(自己的类名,自己的对象)
# 在python3中:super()
# 调用该函数会得到一个特殊的对象,该对象专门用来访问父类中的属性,!!!完全参照mro列表!!!!
# 总结:
# 1. 严格依赖继承的mro列表
# 2. 访问是绑定方法,有自动传值的效果
class Common:
  def __init__(self,name,age,sex):
    self.name=name
    self.age=age
    self.sex=sex
#课程,需要手动添加现在存在的课程
class Course:
  def __init__(self,name,period,price):
    self.name=name
    self.period=period
    self.price=price
  def course_info(self):
    print('%s-%s-%s'%(self.name,self.period,self.price))
#教师
class Teacher(Common):
  def __init__(self,name,age,sex,job_title):
    # Common.__init__(self,name,age,sex)
    super().__init__(name,age,sex)
    self.job_title=job_title
    self.course=[]
    self.students=[]
#学生
class Student(Common):
  def __init__(self,name,age,sex):
    # Common.__init__(self,name,age,sex)
    super().__init__(name,age,sex)
      self.course=[]

joke_teacher=Teacher('joke',18,'male','gold')
zl_student=Student('zl',16,'female')
python=Course('python','3months',3000)
linux=Course('linux','4months',4000)

print(joke_teacher.__dict__)
print(zl_student.__dict__)
Course.course_info(python)
Course.course_info(linux)

#添加课程
joke_teacher.course.append(python)
joke_teacher.course.append(linux)
zl_student.course.append(python)

#为老师添加学生
joke_teacher.students.append(zl_student)
"""

posted on 2018-12-27 08:26  漫天飞雪世情难却  阅读(124)  评论(0编辑  收藏  举报