Python(面向对象Ⅱ)

一、类的空间问题

  1. 何处可以添加对象属性

    class A:
    def __init__(self,name):
    self.name = name
    def func(self,sex):
    self.sex = sex # 类外面可以:
    obj = A('barry')
    obj.age = 18
    print(obj.__dict__) # {'name': 'barry', 'age': 18} # 类内部也可以:
    obj = A('barry') # __init__方法可以。
    obj.func('男') # func 方法也可以。 # 总结:对象的属性不仅可以在__init__里面添加,还可以在类的其他方法或者类的外面添加。
  2. 何处可以添加类的静态属性

    class A:
    def __init__(self,name):
    self.name = name
    def func(self,sex):
    self.sex = sex
    def func1(self):
    A.bbb = 'ccc' # 类的外部可以添加
    A.aaa = 'taibai'
    print(A.__dict__) # 类的内部也可以添加。
    A.func1(111)
    print(A.__dict__) # 总结:类的属性不仅可以在类内部添加,还可以在类的外部添加。
  3. 对象如何找到类的属性

    之前咱们都学习过,实例化一个对象,可以通过点的方式找到类中的属性

    那么他为什么可以找到类中的属性呢 , 如下图 :

    对象查找属性的顺序:先从对象空间找 ------> 类空间找 ------> 父类空间找

    类名查找属性的顺序:先从本类空间找 -------> 父类空间找

    单向不可逆,类名不可能找到对象的属性。

    对象与对象之间原则上互相独立(除去组合这种特殊的关系外)

二、类与类之间的关系

类与类中存在以下关系:

  1. 依赖关系(主从关系)

    将一个类的对象或者类名传到另一个类的方法中

    class Elephant:
    def __init__(self, name):
    self.name = name
    def e_open(self,ref1):
    print(f"{self.name}要开门了,默念三声,开")
    ref1.open_door()
    def e_close(self,ref2):
    print(f"{self.name}要关门了,默念三声,关")
    ref2.close_door()
    class Refrigerator:
    def __init__(self, name):
    self.name = name
    def open_door(self):
    print(f"{self.name}冰箱门被打开了")
    def close_door(self):
    print(f"{self.name}冰箱门被关上了")
    elephant = Elephant('大象')
    haier = Refrigerator('美丽')
    elephant.e_open(haier)
    elephant.e_close(haier)
  2. 组合关系(关联,聚合)

    这三个在代码写法是一样的,但含义上不一样.

    • 关联关系 : 两种事物必须是互相关联的,但是在某些特殊情况下是可以更改和更换的

      class Boy:
      def __init__(self,name):
      self.name = name
      def meet(self,girl_friend=None):
      self.girl_friend = girl_friend
      def have_a_diner(self):
      if self.girl_friend:
      print('%s和%s一起晚饭'%(self.name,self.girl_friend.name))
      self.girl_friend.shopping(self)
      else:
      print('一个人吃饭')
      class Girl:
      def __init__(self,name,age):
      self.name = name
      self.age = age
      def shopping(self,boy_friend):
      print(f"{self.name},{boy_friend.name}一起去购物") wu=Boy("老道")
      flower=Girl("尼姑",48)
      wu.meet(flower)
      wu.have_a_diner() # 注意:此时Boy和Girl两个类之间就是关联关系,两个类的对象紧密联系,其中一个如果没有了,另一个就孤单存在,关联关系其实就是当我需要你,你也属于我,这就是关联关系.
    • 聚合关系 : 属于关联关系中的一种特例,侧重点是xxx和xxx聚合成xxx,各有各的声明周期,互相独立.

    • 组合关系 : 属于关联关系中的一种特例,写法上差不多,组合关系比聚合还要紧密,互相关联,将一个类的对象封装到另一个类的对象的属性中,就叫组合

      组合关系和聚合关系,其实代码上差别不大,以组合关系举例:

      # 设计一个游戏人物类,让实例化几个对象让这几个游戏人物实现互殴的效果,同时增加装备系统.
      class Gamerole:
      def __init__(self,name,ad,hp):
      self.name = name
      self.ad = ad
      self.hp = hp
      def equip_weapon(self,wea):
      self.wea = wea # 组合:给一个对象封装一个属性改属性是另一个类的对象
      class Weapon:
      def __init__(self,name,ad):
      self.name = name
      self.ad = ad
      def weapon_attack(self,p1,p2):
      p2.hp = p2.hp - self.ad - p1.ad
      print('%s 利用 %s 攻击了%s,%s还剩%s血'
      %(p1.name,self.name,p2.name,p2.name,p2.hp)) # 实例化三个人物对象:
      barry = Gamerole('师太',10,100)
      panky = Gamerole('师爷',20,250)
      pillow = Weapon('拖鞋',10) # 给人物装备武器对象。
      barry.equip_weapon(pillow) # 开始攻击
      barry.wea.weapon_attack(barry,panky) # 注意:上面就是组合,只要是人物.equip_weapon这个方法,那么人物就封装了一个武器对象,再利用武器对象调用其类中的weapon_attack方法。
  3. 继承关系

    官方说法 : 继承(英语:inheritance)是面向对象软件技术当中的一个概念。如果一个类别A“继承自”另一个类别B,就把这个A称为“B的子类别”,而把B称为“A的父类别”也可以称“B是A的超类”。继承可以使得子类别具有父类别的各种属性和方法,而不需要再次编写相同的代码。在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。

    1. 面向对象的三大特性 : 封装,继承,多态

    2. 什么是继承

      B继承A类,B就叫做A的子类,A叫做B的父类,基类,超类,B类以及B类的对象使用A类的所有的属性以及方法

      举例如下 :

      # 正常类的用法
      class Person:
      def __init__(self,name,sex,age):
      self.name = name
      self.age = age
      self.sex = sex
      class Cat:
      def __init__(self,name,sex,age):
      self.name = name
      self.age = age
      self.sex = sex
      class Dog:
      def __init__(self,name,sex,age):
      self.name = name
      self.age = age
      self.sex = sex # 继承的用法:
      class Aniaml(object): # 在这里 Aminal 叫做父类,基类,超类。
      def __init__(self,name,sex,age):
      self.name = name
      self.age = age
      self.sex = sex
      class Person(Aniaml): # Person: 子类,派生类。
      pass
      class Cat(Aniaml): # Cat: 子类,派生类。
      pass
      class Dog(Aniaml): # Dog: 子类,派生类。
      pass
    3. 继承的优点

      1. 减少代码重复
      2. 增加类的耦合性
      3. 代码规范化合理化
    4. 继承分类

      1. 单继承

        • 类名对象执行父类方法,子类以及子类对象只能调用父类的属性以及方法,不能操作(增删改)

          class Aniaml(object):
          type_name = '动物类'
          def __init__(self,name,sex,age):
          self.name = name
          self.age = age
          self.sex = sex
          def eat(self):
          print(self)
          print('吃东西')
          class Person(Aniaml):
          pass
          class Cat(Aniaml):
          pass
          class Dog(Aniaml):
          pass # 类名:
          print(Person.type_name) # 可以调用父类的属性,方法。
          Person.eat(111)
          print(Person.type_name) # 对象:
          # 实例化对象
          p1 = Person('师太','女',20)
          print(p1.__dict__) # 对象执行类的父类的属性,方法。
          print(p1.type_name)
          p1.type_name = '666'
          print(p1)
          p1.eat()
        • 执行顺序

          class Aniaml(object):
          type_name = '动物类'
          def __init__(self,name,sex,age):
          self.name = name
          self.age = age
          self.sex = sex
          def eat(self):
          print(self)
          print('吃东西')
          class Person(Aniaml):
          def eat(self):
          print('%s 吃饭'%self.name)
          class Cat(Aniaml):
          pass
          class Dog(Aniaml):
          pass
          p1 = Person('lala','女',20)
          # 实例化对象时必须执行__init__方法,类中没有,从父类找,父类没有,从object类中找。
          p1.eat()
          # 先要执行自己类中的eat方法,自己类没有才能执行父类中的方法。
        • 同时执行类以及父类方法

          方法一

          子类的方法中写上:父类.func(对象,其他参数)

          class Aniaml(object):
          type_name = '动物类'
          def __init__(self,name,sex,age):
          self.name = name
          self.age = age
          self.sex = sex
          def eat(self):
          print('吃东西')
          class Person(Aniaml):
          def __init__(self,name,sex,age,mind):
          Aniaml.__init__(self,name,sex,age) # 方法一
          self.mind = mind
          def eat(self):
          super().eat()
          print('%s 吃饭'%self.name)
          class Cat(Aniaml):
          pass
          class Dog(Aniaml):
          pass # 方法一: Aniaml.__init__(self,name,sex,age)
          p1 = Person('师太','女',20,'武艺高强')
          print(p1.__dict__)

          方法二

          利用super,super().func(参数)

          class Aniaml(object):
          type_name = '动物类'
          def __init__(self,name,sex,age):
          self.name = name
          self.age = age
          self.sex = sex
          def eat(self):
          print('吃东西')
          class Person(Aniaml):
          def __init__(self,name,sex,age,mind):
          # super(Person,self).__init__(name,sex,age)
          # super()括号内可不写Person,self 在python自动执行此操作
          super().__init__(name,sex,age) # 方法二
          self.mind = mind
          def eat(self):
          super().eat()
          print('%s 吃饭'%self.name)
          class Cat(Aniaml):
          pass
          class Dog(Aniaml):
          pass
          p1 = Person('师太','女',20,'武艺高强')
          print(p1.__dict__)
      2. 多继承

        class ShenXian:
        def fei(self):
        print("飞")
        class Monkey:
        def pi(self):
        print("皮")
        class SunWukong(ShenXian, Monkey): # 孙悟空是神仙,同时也是也只猴
        pass
        sxz = SunWukong() # 孙悟空
        sxz.pi() # 此时猴子皮
        sxz.fei() # 此时会飞

        当两个超类中出现了重名方法的时候,这时就涉及到如何查找超类方法的这个问题.即MRO(method resolution order) 问题. 在python中这是个很复杂的问题. 因为在不同的python版本中使用的是不同的算法来完成MRO的.

    5. python中类的种类(继承需要) :

      class A:
      pass
      class B(A):
      pass
      class C(A):
      pass
      class D(B, C):
      pass
      class E:
      pass
      class F(D, E):
      pass
      class G(F, D):
      pass
      class H:
      pass
      class Foo(H, G):
      pass
      1. python2.2之前 : 都是经典类,

      2. python2.2-python2.7存在两种类型 :经典类,新式类

      3. python3x只有新式类

        • 经典类 : 基类不继承object,查询规则依靠深度优先原则(画图)

          从头开始,从左往右.,一条路跑到头,然后回头,继续一条路跑到头,就是经典类的MRO算法

          Foo-> H -> G -> F -> E -> D -> B -> A -> C

        • 新式类 : 基类必须继承object,查询规则依靠mro算法,mro是一个有序列表L,在类被创建时就计算出来。

          通用计算公式为:

          mro(Child(Base1,Base2))=[Child]+merge( mro(Base1),mro(Base2),[Base1,Base2])
          (其中Child继承自Base1, Base2)

          merge操作示例:

          如计算merge( [E,O], [C,E,F,O], [C] )
          有三个列表 : ① ② ③
          1 merge不为空,取出第一个列表列表①的表头E,进行判断
          各个列表的表尾分别是[O], [E,F,O],E在这些表尾的集合中,因而跳过当前当前列表
          2 取出列表②的表头C,进行判断
          C不在各个列表的集合中,因而将C拿出到merge外,并从所有表头删除
          merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] )
          3 进行下一次新的merge操作 ......
          ---------------------

          计算mro(A)方式:

          # mro(A)内部运行情况如下
          mro(A) = mro( A(B,C) )
          原式= [A] + merge( mro(B),mro(C),[B,C] )
          mro(B) = mro( B(D,E) )
          = [B] + merge( mro(D), mro(E), [D,E] ) # 多继承
          = [B] + merge( [D,O] , [E,O] , [D,E] ) # 单继承mro(D(O))=[D,O]
          = [B,D] + merge( [O] , [E,O] , [E] ) # 拿出并删除D
          = [B,D,E] + merge([O] , [O])
          = [B,D,E,O]
          mro(C) = mro( C(E,F) )
          = [C] + merge( mro(E), mro(F), [E,F] )
          = [C] + merge( [E,O] , [F,O] , [E,F] )
          = [C,E] + merge( [O] , [F,O] , [F] ) # 跳过O,拿出并删除
          = [C,E,F] + merge([O] , [O])
          = [C,E,F,O]
          原式= [A] + merge( [B,D,E,O], [C,E,F,O], [B,C])
          = [A,B] + merge( [D,E,O], [C,E,F,O], [C])
          = [A,B,D] + merge( [E,O], [C,E,F,O], [C]) # 跳过E
          = [A,B,D,C] + merge([E,O], [E,F,O])
          = [A,B,D,C,E] + merge([O], [F,O]) # 跳过O
          = [A,B,D,C,E,F] + merge([O], [O])
          = [A,B,D,C,E,F,O]
          ---------------------
          # python提供了简单的方法查询
          python(mro(A)) # 此时会打印出A的超级之间的排序关系

20.Python略有小成(面向对象Ⅱ)的更多相关文章

  1. 19.Python略有小成(面向对象Ⅰ)

    Python(面向对象Ⅰ) 一.面向对象初识 回顾面向过程编程与函数式编程 # 面向过程编程 测量对象的元素个个数. s1 = 'fjdsklafsjda' count = 0 for i in s1 ...

  2. Python之面向对象一

    引子 小游戏:人狗大战 角色:人和狗 角色属性:姓名,血量,战斗力和性别(种类) 技能:打/咬 用函数实现人打狗和狗咬人的情形 def Dog(name,blood,aggr,kind): dog = ...

  3. [ python ] 初始面向对象

    首先,通过之前学习的函数编写一个 人狗大战 的例子. 分析下这个需求,人 狗 大战  三个事情.角色:人.狗动作:狗咬人,人打狗 先创建人和狗两个角色: def person(name, hp, ag ...

  4. Python -面向对象(一 基本概念)

    一 Python简单介绍 Python是一个可移植的面向对象的脚本语言. Python尽管是一个脚本语言,但也是一个全然面向对象的语言.由于它设计之初把易用性做为很重要的一个考量标准,所以用起来很简洁 ...

  5. Python之面向对象封装

    Python之面向对象封装 封装不是单纯意义的隐藏 什么是封装: 将数据放在一个设定好的盒子里,并标出数据可以实现的功能,将功能按钮外露,而隐藏其功能的工作原理,就是封装. 要怎么封装: 你余额宝有多 ...

  6. Python之面向对象slots与迭代器协议

    Python之面向对象slots与迭代器协议 slots: # class People: # x=1 # def __init__(self,name): # self.name=name # de ...

  7. python初始面向对象

    阅读目录 楔子 面向过程vs面向对象 初识面向对象 类的相关知识 对象的相关知识 对象之间的交互 类命名空间与对象.实例的命名空间 类的组合用法 初识面向对象小结 面向对象的三大特性 继承 多态 封装 ...

  8. Python 基础 面向对象之二 三大特性

    Python 基础 面向对象之二 三大特性 上一篇主要介绍了Python中,面向对象的类和对象的定义及实例的简单应用,本篇继续接着上篇来谈,在这一篇中我们重点要谈及的内容有:Python 类的成员.成 ...

  9. Python 【面向对象】

    前言 Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的.本章节我们将详细介绍Python的面向对象编程. 如果你以前没有接触过面向对象的编程语言 ...

随机推荐

  1. 洛谷p2370yyy2015c01的U盘题解

    没什么特殊的想法 就是看自己很久没有更新关于题解类的文章了而已 (其实这是我好久之前做的, 只是把它从洛谷博客搬到了这里而已) 题目 首先分析题目要二分 他长成这个亚子太二分了 所以就要二分 最好是先 ...

  2. 洛谷 P1621 集合

    目录 题目 思路 \(Code\) 题目 P1621 集合 思路 并查集+埃氏筛,一开始连通块的个数是\(b-a+1\)个,在筛素数的过程中只要当前素数大于\(p\)就对该素数筛出来的数进行判断,如果 ...

  3. 第03组 Alpha冲刺(4/4)

    队名:不等式方程组 组长博客 作业博客 团队项目进度 组员一:张逸杰(组长) 过去两天完成的任务: 文字/口头描述: 制定了初步的项目计划,并开始学习一些推荐.搜索类算法 GitHub签入纪录: 暂无 ...

  4. 再说js隐式转换

    再说js隐式转换 自己整理的一个整体规则如下: Date 默认 走 toString, 如果 toString 返回的是对象, 那么查看 valueOf 其他对象的转换, 默认走 valueOf, 但 ...

  5. RMQ问题(超详细!!!)

    一.简介 RMQ是询问某个区间内的最大值或最小值,暴力解法对每个询问区间用循环找最值,当n.q>10000会TLE. 常用RMQ的求解方法——ST算法. ST算法通常用在要多次询问一些区间的最值 ...

  6. Spring事务经典案例-银行转账

    1.entity实体类 2.dao层 3.dao实现类 4.service层 5.serviceimpl层 6.大配置.xml <?xml version="1.0" enc ...

  7. shell for 循环演示

    test.sh #!/bin/bash for skill in Ada Coffe Action Java; do echo "I am good at ${skill}Script&qu ...

  8. [技术博客]React Native——HTML页面代码高亮&数学公式解析

    问题起源 原有博文显示时代码无法高亮,白底黑字的视觉效果不好. 原有博文中无法解析数学公式,导致页面会直接显示数学公式源码. 为了解决这两个问题,尝试了一些方法,最终利用开源类库实现了页面美化. (失 ...

  9. SpringMvc的 @Valid 拦截到的异常如何抛出

    SpringMvc中,校验参数可以使用 @Valid 注解,同时在相应的对象里使用 @NotBlank( message = "昵称不能为空")@NotNull( message ...

  10. quartus仿真提示: Can't launch the ModelSim-Altera software

    quartus仿真提示: Can't launch the ModelSim-Altera software 2017年07月13日 17:54:50 小怪_tan 阅读数:3255   路径中的结尾 ...