• 20.Python略有小成(面向对象Ⅱ)


    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的超级之间的排序关系
            
  • 相关阅读:
    centos 安装Phpstorm
    PostgreSQL 里面的 BIGSERIAL
    如何下载symfony
    换行
    javaScript 真经 小感 this 指向
    css3 抖动
    jq 抖动效果
    还是 js 替代 vw vh 了
    常用 Math 属性及方法
    js 判断浏览器类型及版本
  • 原文地址:https://www.cnblogs.com/chenshuo531702820/p/11158509.html
Copyright © 2020-2023  润新知