python面向对象之类空间问题及类之间的关系

类空间问题

  1. 从空间角度研究类

    class A:
        address = '美丽富饶的沙河'
        def __init__(self, name):
            self.name = name
        def func(self):
            if self.name == 'dsb':
                self.skins = '吉利服'
        def func1(self):
            print(self.__dict__)
            A.aaa = '易水寒'
    
    obj = A('dsb')
    # 类外面可以给对象封装属性
    respons = input('太白帅不帅!')
    if respons == '帅':
        obj.weapon = 'AWM'
    print(obj.__dict__)
    
    # 类内部封装属性
    obj.func()
    print(obj.__dict__)
    
    # 使用类名也可以添加属性
    A.teamp = '39.5' # 用类名.添加
    print(A.__dict__)
    A.func1(obj) # 利用类里的方法添加
    print(A.__dict__)
    
    # 属性查找顺序
    class Person:
        mind = '有思想'
        language = '会使用语言'
        def __init__(self, name, age):
            self.name = name
            self.age = age
        def work(self):
            print('人类一般都需要工作')
    
    p1 = Person('dsb', 21)
    print(p1.mind) # 对象空间没有就去类空间里找 
    p1.mind = '无脑' # 创建一个mind属性
    print(p1.mind) # 是在对象空间里创建
    print(Person.mind) # 类空间里的mind不变
    
    # 对象如果查询一个属性: 对象空间  ----> 类空间 ----> 父类空间  --->
    # 类查询一个属性: 类空间  ----> 父类空间  ---->
    # 单向不可逆
    
    # 对象与对象之间原则上互相独立(除去组合这种特殊的关系之外).

类与类之间的关系

  1. 依赖关系: 将一个类名或者类的对象传给另一个类的方法中.

    # 举例--大象进冰箱
    class Elephant:
        def __init__(self,name):
            self.name = name
        def open(self,ref1):
            print(f"大象{self.name}默念三声:芝麻开门")
            ref1.open_door()
        def close(self,ref1):
            print(f"大象{self.name}默念三声:芝麻关门")
            ref1.close_door()
    class Refrigerate:
        def __init__(self,name):
            self.name = name
        def open_door(self):
            print(f"{self.name}冰箱的门被打开了...")
        def close_door(self):
            print(f"{self.name}冰箱的门被关上了...")
    
    ele = Elephant('奇奇')
    ref = Refrigerate('海尔')
    ele.open(ref)
    ele.close(ref)
    '''结果:
    大象奇奇默念三声:芝麻开门
    海尔冰箱的门被打开了...
    大象奇奇默念三声:芝麻关门
    海尔冰箱的门被关上了...
    '''
    # 依赖关系: 将一个类的类名或者对象传给另一个类的方法中.
  2. 组合关系(关联组合聚合)

    # 组合:(聚合,组合,关联)
    # 组合: 将一个类的对象封装成另一个类的对象的属性.
    class Boy:
        def __init__(self,name):
            self.name = name
        def meet(self,girl_friend=None):
            self.girl_friend = girl_friend
        def have_diner(self):
            if self.girl_friend:
                print(f"{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,a):
            print(f"{self.name},{a.name}一起去购物")
    
    wu = Boy('吴超')
    flower = Girl('如花',48)
    wu.meet(flower)
    wu.have_diner()
    
    # 上面例题的难点:
    # 一个类的方法只能有此类的对象去调用.
    # 一个类的方法的第一个self只接受此类的对象.
    
    # 模拟英雄联盟写一个游戏人物的类(升级题).
    # 要求:
    # 1. 创建一个 Game_role的类.
    # 2. 构造方法中给对象封装name,ad(攻击力),hp(血量).三个属性.
    # 3. 创建一个attack方法,此方法是实例化两个对象,互相攻击的功能:
    # 例: 实例化一个对象 盖伦,ad为10, hp为100
    # 实例化另个一个对象 剑豪 ad为20, hp为80
    # 盖伦通过attack方法攻击剑豪,此方法要完成 '谁攻击谁,谁掉了多少血,  还剩多少血'的提示功能.
    
    class GameRole:
        def __init__(self, name, ad, hp):
            self.name = name
            self.ad = ad
            self.hp = hp
        def attack(self,p1):
            p1.hp = p1.hp - self.ad
            print(f'{self.name}攻击{p1.name},{p1.name}掉了{self.ad}血,还剩{p1.hp}血')
        def equit_weapon(self,wea):
            self.weapon = wea 
            # 组合: 给gailun这个对象封装了一个为weapon属性,属性值为wea == great_sword对象
    class Weapon:
        def __init__(self, name, ad):
            self.name = name
            self.ad = ad
        def weapon_attack(self, p1, p2):
            # print(self)
            p2.hp = p2.hp - self.ad
            print(f'{p1.name}利用{self.name}给了{p2.name}一下,{p2.name}还剩{p2.hp}血')
    
    gailun = GameRole('草丛伦', 10, 100)
    jianhao = GameRole('风男', 20, 80)
    gailun.attack(jianhao)
    gailun.attack(jianhao)
    gailun.attack(jianhao)
    '''结果:
    草丛伦攻击风男,风男掉了10血,还剩70血
    草丛伦攻击风男,风男掉了10血,还剩60血
    草丛伦攻击风男,风男掉了10血,还剩50血
    '''
    
    # 利用武器攻击
    gailun = GameRole('盖伦', 10, 100)
    zhaoxin = GameRole('赵信', 20, 90)
    great_sword = Weapon('大宝剑', 30)
    spear = Weapon('红缨枪', 40)
    great_sword.weapon_attack(gailun, zhaoxin)
    ''' 结果: 盖伦利用大宝剑给了赵信一下,赵信还剩60血 '''
    # 上面需要解决的问题: 发起武器攻击的发起者应该是人类,而不是great_sword武器对象.
    # 但是weapon_attack只能有Weapon类的对象去调用.
    
    gailun = GameRole('盖伦', 10, 100)
    zhaoxin = GameRole('赵信', 20, 90)
    great_sword = Weapon('大保健', 30)
    gailun.equit_weapon(great_sword)  # 依赖关系
    gailun.weapon.weapon_attack(gailun, zhaoxin)
    ''' 结果: 盖伦利用大宝剑给了赵信一下,赵信还剩60血 '''
  3. 继承关系

    1. 什么是继承?

      专业角度: B 继承 A类, B就叫做A的子类,派生类, A叫做B的父类,基类,超类. B类以及B类的对象使用A类的所有的属性以及方法.

      字面意思: 继承就是继承父母所有的资产.

      继承分为单继承,多继承.

    2. 继承的优点.

      1. 节省代码.
      2. 增强的耦合性.
      3. 代码规范化.
    3. 单继承.

      # 普通面向对象编程
      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
      # 都有name,sex,age 代码重复       
      # 利用继承写        
      class Animal:
          def __init__(self, name, age, sex):
              self.name = name
              self.age = age
              self.sex = sex
      class Person(Animal):
          pass
      class Dog(Animal):
          pass
      class Cat(Animal):
          pass
      # 下面三个类都可以调用父类的属性,降低了代码重复性
      
      # 如何调用类中的属性与方法
      class Animal(object):
          live = '有生命的'
          def __init__(self, name, age, sex):
              self.name = name
              self.age = age
              self.sex = sex
          def eat(self):
              print(f'self----> {self}')
              print('动物都需要进食')
      class Person(Animal):
          pass
      
      # 1.从类名执行父类的属性.
      print(Person.__dict__)
      print(Person.live)
      Person.eat()
      
      # 2. 从对象执行父类的一切.
      # 实例化对象一定一定会执行三件事. 一定会执行__init__ 子类没有就去父类中找
      p1 = Person('dsb', 21, 'laddy_boy')
      print(p1.live)
      p1.eat()
      
      Person.live = 'xxx'
      print(Person.live)
      # 注意: 子类以及子类对象只能调用父类的属性以及方法,不能操作(增删改).
      
      class Animal(object):
          live = '有生命的'
          def __init__(self, name, age, sex):
              self.name = name
              self.age = age
              self.sex = sex
          def eat(self):
              print(f'self----> {self}')
              print('动物都需要进食')
      class Person(Animal):
          def eat(self):
              print('人类需要进食')
      
      p1 = Person('dsb', 21, 'laddy_boy')
      # 子类将父类的方法覆盖了,(重写父类的方法)
      p1.eat = '李业'
      p1.eat()# 不能执行,以为eat已被修改为'李业'  # 对象查找顺序先从对象空间找名字, 子类找名字, 父类找名字.
      
      # 如何既要执行父类方法又要执行子类方法
      # 两种解决方式:
      class Animal:
          live = '有生命的'
          def __init__(self, name, age, sex):
              self.name = name
              self.age = age
              self.sex = sex
          def eat(self):
              print(f'self----> {self}')
              print('动物都需要进食')
      class Person(Animal):
          def __init__(self,name, age, sex, hobby):
              # 方法一:
              Animal.__init__(self, name, age, sex) # 类名直接调用
              # 方法二:
              # super(Person, self).__init__(name, age, sex)
              # super().__init__(name, age, sex) # 利用super
              self.hobby = hobby
          def eat(self):
              print('人类需要进食')
              super().eat()
      p1 = Person('怼怼哥', 23, '不详','吹牛逼')
      p1.eat()
      # super(). 主动调用父类中的函数
    4. 多继承.

      class God:
          def __init__(self,name):
            self.name = name
          def fly(self):
              print('会飞')
          def climb(self):
              print('神仙累了也需要爬树')
      class Monkey:
          def __init__(self,sex):
              self.sex = sex
          def climb(self):
              print('爬树')
      class MonkeySun(God, Monkey):
          pass
      # 多继承的难点就是继承顺序的问题
      sun = MonkeySun()
      sun.climb()
      '''
      这里需要补充一下python中类的种类(继承需要):
      在python2x版本中存在两种类.:
        ⼀个叫经典类. 在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写.
        ⼀个叫新式类. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。
      python3x版本中只有一种类:
      python3中使⽤的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object
      '''
      # 经典类的继承顺序: 在经典类中采⽤的是深度优先,遍历⽅案. 什么是深度优先. 就是⼀条路走到头. 然后再回来. 继续找下⼀个.
      
      # 新式类的继承顺序: mro序列
      # mro算法  面试中有可能会遇到
      """
      MRO是一个有序列表L,在类被创建时就计算出来。
      通用计算公式为:
      mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )
      (其中Child继承自Base1, Base2)
      
      如果继承至一个基类:class B(A)
      这时B的mro序列为
      mro( B ) = mro( B(A) )
      = [B] + merge( mro(A) + [A] )
      = [B] + merge( [A] + [A] )
      = [B,A]
      
      如果继承至多个基类:class B(A1, A2, A3 …)
      这时B的mro序列
      mro(B) = mro( B(A1, A2, A3 …) )
      = [B] + merge( mro(A1), mro(A2), mro(A3) ..., [A1, A2, A3] )
      = ...
      
      计算结果为列表,列表中至少有一个元素即类自己,如上述示例[A1,A2,A3]。merge操作是C3算法的核心。
      
      表头和表尾
      表头:列表的第一个元素
      表尾:列表中表头以外的元素集合(可以为空)
      示例: 列表:[A, B, C]--->表头是A,表尾是B和C
      
      列表之间的+操作
      +操作:[A] + [B] = [A, B]
      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操作 ......
      """
      # 计算示例
      class O:
          pass
      class D(O):
          pass
      class E(O):
          pass
      class F(O):
          pass
      class B(D,E):
          pass
      class C(E,F):
          pass
      class A(B,C):
          pass
      a = A()
      a.func()
      '''
      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])
             = [B,D] + merge([O], [E,O], [E])
             = [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])
             = [C,E,F,O]
      
      mro(A) = mro(A(B,C))
             = [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])
             = [A,B,D,C] + merge([E,O], [E,F,O])
             = [A,B,D,C,E] + merge([O], [F,O])
             = [A,B,D,C,E,F,O]
      '''
      # 工作中用mro()方法研究新式类的继承顺序
      print(A.mro())

转载于:https://www.cnblogs.com/changyifei-8/p/11153428.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值