python面向對象基礎-01

  • 2019 年 10 月 7 日
  • 筆記

面向對象(OOP)基本概念

前言

話說三國時期曹軍於官渡大敗袁紹,酒席之間,曹操詩興大發,吟道:喝酒唱歌,人生真爽! 眾將直呼:"丞相好詩",於是命印刷工匠刻板印刷以流傳天下;    待工匠刻板完成,交與曹操一看,曹操感覺不妥,說道:"喝酒唱歌,此話太俗,應改為'對酒當歌'較好",於是名工匠重新刻板,當時還沒有出現活字印刷術,如果樣板要改,只能重新刻板,工匠眼看連夜刻版之工,徹底白費,心中叫苦不迭。可也只得照辦。    版樣再次出來請曹操過目,曹操細細一品,覺得還是不好,說」人生真爽太過直接,應該改問語才夠意境,因此應改為『對酒當歌,人生幾何?』「,於是....    在活字印刷術還沒出現之前,如果版樣有改動,只能重新雕刻。而且在印刷完成後,這個樣板就失去了它的價值,如果需要其他樣板只能重新雕刻。而活字印刷術的出現就大大改善了印刷技術。如上例」喝酒唱歌,人生真爽「,如果用活字印刷,只需要改四個字就可,其餘工作都未白做。豈不快哉!!    活字印刷也反應了OOP。當要改動時,只需要修改部分,此為 可維護;當這些字用完後,並非就完全沒有價值了,它完全可以在後來的印刷中重複使用,此乃 可復用;此詩若要加字,只需另刻字加入即可,這就是 可擴展;字的排列可以橫排,也可以豎排,此是 靈活性好。
# 上述案列反應了面向對象的優點,即可維護性高,擴展性強,復用性高!  #   這些特點非常適用於用戶需求變化頻繁的互聯網應用程式,這是學習面向對象的重要原因  #   但是面向對象設計的程式需涉及類與對象,相應的複雜度會提高!  #  # 並非所有程式都需要較高的擴展性,例如系統內核,一旦編寫完成,基本不會再修改,使用面向過程來設計則更適用

面向對象

面向對象: # 是一種編程思想,是前輩們總結的編程經驗,指導程式設計師如何編寫出更好的程式

核心: # 對象

程式就是一系列對象的集合,程式設計師負責調度控制這些對象來交互著完成任務 在面向對象中程式設計師的角度發生了改變,從具體的操作者變成了指揮者。

強調:對象不是憑空產生的,需要我們自己設計

面向對象的優缺點

'''      優點:          1.可擴展性高          2.靈活性高          3.重用性高        缺點:          1.程式的複雜度提高了          2.無法準確預知結果  '''

使用場景: # 對擴展性要求較高的程式,通常是直接面向用戶的,例如qq 微信

注意點: # 不是所有的程式都要採用面向對象,要根據實際需求來選擇

面向對象的兩大核心: # 類與對象

'''    類即類型、類別,是一種 抽象概念        是一系列具備相同特徵和相同行為的對象的集合  ''' 

對象

'''      對象就是具體存在的某個事物,具備自己的特徵和行為          對象就是特徵和技能的結合體  '''

類和對象的關係

'''      類包含一系列對象      對象屬於某個類        在現實中先有對象再有類,程式中先有類再有對象          我們必須先告訴電腦這類的對象有什麼特徵有什麼行為  '''

結論: # 在面向對象編程時,第一步需要考慮需要什麼樣的對象,對象具備什麼樣的特徵和行為,從而根據這些資訊總結出需要的類

用面向對象思想編程

類的定義語法及類名書寫規範

class 類的名稱:      # 類中的內容,描述屬性和技能      # 描述屬性用變數      # 描述行為用函數    '''      類名書寫規範:          1.見名知意          2.名稱是大駝峰式(駝峰就是單詞首字母大寫,大駝峰就是第一個字母大寫,小駝峰是第一個字母小寫)          3.其他規範與變數大致相同  '''

屬性

'''  屬性可以寫在類中  類中的屬性,是對象公共的    也可以寫在對象中  對象中的屬性,每個對象獨特的(不一樣的)    如果類和對象中存在同樣的屬性,先訪問對象,如果沒有再訪問類  '''

屬性的增刪改查

'''  增加屬性      對象變數名稱.屬性名稱 = 屬性值      egon.male = 'male'  刪除屬性      del 對象的變數名稱.屬性名稱      del egon.male  修改屬性      對象.屬性 = 新的值  查看所有屬性,訪問的是對象的所有屬性      對象.__dict__  --> dict 可以訪問調用者自身的名稱空間    訪問他的類      對象.__class__ 返回類  '''
class Student:      '''      這是Student類的注釋      '''      def __init__(self, name):          self.name = name      class TeachOfOldBoy:      company = 'oldboy'        def __init__(self, name):          self.name = name      # ---------- 對象新增、修改、查看、刪除屬性 -------------  xuzhaolong = Student('xzl')  print(xuzhaolong.name)  # 對象.屬性 --> 訪問對象的屬性  # xzl  # print(xuzhaolong.age)  # 訪問不存在的屬性會報錯'Student' object has no attribute 'age'  xuzhaolong.age = 18  # 對象.屬性 = 值 --> 為對象添加新屬性  print(xuzhaolong.age)  # 18  xuzhaolong.age = 28  # 對象.屬性 = 新值 --> 修改屬性的值(如果該對象已有此屬性)  print(xuzhaolong.age)  # 28  del xuzhaolong.age   # 刪除對象的屬性  # print(xuzhaolong.age)  # 會報錯,屬性已被刪除,類中(屬性的查找順序:對象-->父類-->...如果還有父類,其他父類...-->Object)沒有這個屬性,AttributeError: 'Student' object has no attribute 'age'    print(TeachOfOldBoy.__dict__)  # __dict__查看調用者的名稱空間里的名字  # {'__module__': '__main__', 'company': 'oldboy', '__init__': <function TeachOfOldBoy.__init__ at 0x0000026D1AC8A9D8>, '__dict__': <attribute '__dict__' of 'TeachOfOldBoy' objects>, '__weakref__': <attribute '__weakref__' of 'TeachOfOldBoy' objects>, '__doc__': None}  print(xuzhaolong.__dict__)  # {'name': 'xzl', 'age': 28}    # ---------- __class__ 查看調用者所屬類型(python里類也是一種數據類型) -------------  print(TeachOfOldBoy.__class__)  # __class__ 查看調用者所屬類  # <class 'type'>  print(xuzhaolong.__class__)  # <class '__main__.Student'>    # ---------- __doc__ 查看調用者的注釋  -------------  print(TeachOfOldBoy.__doc__)  # __doc__ 查看調用者的注釋  # None  print(Student.__doc__)  # __doc__ 查看調用者所屬類的注釋  #  #     這是Student類的注釋  #  print(xuzhaolong.__doc__)  # __doc__ 查看調用者所屬類的注釋  #  #     這是Student類的注釋  #    # ------------ 類中的屬性與對象 -----------------  egon = TeachOfOldBoy('egon')  print(egon.company)  # oldboy  egon.company = 'OldBoy'  print(egon.company)  # 修改對象的繼承的屬性不影響類中的屬性  # OldBoy  print(TeachOfOldBoy.company)  # oldboy

屬性的查找順序: # 屬性的查找順序:先找自己的,再找類的,再父類。。。。一直往上找到object,再沒有就報錯

對象初始化__inint__

'''  __init__方法      特點          1.當實例化對象時,會自動執行__init__方法          2.會自動將對象作為第一個參數傳入,對象參數名稱為self,self這個名字可以改,但不建議(一眼就知道是對象本身了)        功能          用戶給對象賦初始值  '''  # 初始化,不僅僅只是賦初值,還可以做一些其他操作,來保證對象的正常生成
'''      之前十個老師,每個老師都要輸姓名年齡等,而屬性的值又不一樣,就不能直接定義成類的屬性      每定義一個對象都要寫一次,很麻煩        那麼我們可以使用函數來簡化這個賦值操作      class Cls:  # 定義一個類          pass        def init(obj, kind, color, age):  # 定義一個方法來簡化給對象添加(訂製)屬性          obj.kind = kind  # 即 對象.屬性 = 值(變數的) --> 像什麼? 給對象添加屬性嘛          obj.color = color          obj.age = age        obj1 = Cls()  # 實例化出一個對象      init(obj1, "泰日天", '棕色', 2)  # 通過調用 init 函數來給該對象添加屬性      obj2 = Cls()      init(obj2, "拆家犬", '黑白', 1)      # 這樣子就有了兩個對象,且都已經有了各自的屬性了    '''      class Dog:      def __init__(self, kind, color, age):          # print(locals())  # {'age': 2, 'color': '棕色', 'kind': '泰日天', 'self': <__main__.Dog object at 0x000002985BE586D8>}          self.kind = kind          self.color = color          self.age = age          # __init__ 函數不允許寫返回值(不能寫,只能返回None,寫return None 沒有意思) 規定如此        '''          不過在類裡面直接寫這個 init 函數會更方便(python內部做了一些處理)          如上,當實例化對象時,會自動執行這個 __init__ 方法              會自動將調用這個類實例化的對象作為第一個參數傳入,對象參數名稱為self      '''      # 那麼在實例化的時候就可以簡寫成這樣了,四行變兩行  teidi = Dog("泰日天", '棕色', 2)  # print(teidi.__dict__)  # {'kind': '泰日天', 'color': '棕色', 'age': 2}  erha = Dog("拆家犬", '黑白', 1)      '''  其實上面的寫法還可以有優化,那個__init__ 函數還可以寫得更簡潔一點(參數越多越明顯)      def __init__(self, kind, color, age):          lcs = locals()          lcs.pop('self')          self.__dict__.update(lcs)        上面寫法中的locals()內置函數在 __init__ 函數中,可以獲取 __init__ 函數名稱空間里的那些名字,它是一個字典          # print(locals())  # {'age': 2, 'color': '棕色', 'kind': '泰日天', 'self': <__main__.Dog object at 0x000002985BE586D8>}          我們將其賦給一個中間字典接收,將多餘的 self 鍵值對去掉,就是我們對象想要的屬性          而對象.__dict__正好也是一個字典          # print(teidi.__dict__)  # {'kind': '泰日天', 'color': '棕色', 'age': 2}          都是字典?字典的update()方法還記得嗎?          將這個中間字典update()到對象的.__dict__ 中,即完成了對象的屬性添加          self.__dict__.update(lcs)  '''

備註:關於python內一些 __名字__ 這種屬性是什麼情況,可以參考這篇部落格哦(都說不重要,但總有我這樣的好奇寶寶嘛)~ Python常用內建方法:__init__,__new__,__class__的使用詳解

綁定方法與非綁定方法

對象的精髓所在就是將數據和處理數據的函數整合到一起了,這樣一來,拿到一個對象就同時拿到了需要處理的數據以及處理數據的函數

'''  ******* 這一塊基礎概念是重點 *******  對象綁定方法:self --> 默認傳入對象      默認情況下,類中的方法都是對象綁定方法        當使用對象調用時          其特殊之處在於調用該函數時會自動傳入對象本身作為第一個參數      當使用類名來調用時就是一個普通函數,有幾個參數就傳幾個參數      類綁定方法:@classmethod              cls(加上@classmethod裝飾後自己將self改為cls(class是關鍵字)) --> 默認傳入類      給類的抽象方法,默認傳入類作為參數      特殊之處:不管用類還是對象調用,都會自動傳入類本身,作為第一個參數        何時綁定給對象:當函數邏輯需要訪問對象中的數據時      何時綁定給類:當函數邏輯需要訪問類中的數據時      非綁定方法:@staticmethod      裝飾成普通函數,不管誰調都一樣          既不需要訪問類的數據也不需要訪問對象的數據      定義時有幾個參數調用時就需要傳入幾個參數      '''  class Dog:      species = 'dog'      # 初始化方法 __init__ 也屬於對象綁定方法      def __init__(self, kind, nickname, skill):          self.kind = kind          self.nickname = nickname          self.skill = skill        # 這就屬於一個對象綁定方法,默認將對象作為第一個參數傳入(調用的時候不需要手動傳入)      def introduce(self):          print(f"我是{self.kind},我能{self.skill},人送外號{self.nickname}")        # 類綁定方法      @classmethod      def tell_species(cls):  # 先寫裝飾器再寫函數,默認參數就是cls了,寫完函數再裝飾的話,記得把self換成cls,表示參數是一個類          print(f"我的物種是{cls.species}")        # 非綁定方法(既不需要傳入類,也不需要傳入對象)      @staticmethod      def normal_func(arg1, arg2):          print(f"參數一:{arg1} 參數二:{arg2},這只是一個普通方法啦~")    taidi = Dog('泰迪', '泰日天', '日天')  erha = Dog('二哈', '拆家犬', '拆家')      # --------綁定對象方法的調用  taidi.introduce()  erha.introduce()  # 我是泰迪,我能日天,人送外號泰日天  # 我是二哈,我能拆家,人送外號拆家犬  Dog.introduce(erha)  # 類調用對象的方法要手動把對象傳入進去  # 我是二哈,我能拆家,人送外號拆家犬    # --------類綁定方法調用  Dog.tell_species()  taidi.tell_species()  # 可以直接調用,無需手動傳入 class  # 我的物種是dog  # 我的物種是dog    # --------非綁定方法調用  Dog.normal_func(1, 2)  # 非綁定方法,定義時有幾個參數,調用時就要傳幾個參數  taidi.normal_func(1, 2)  # 非綁定方法,定義時有幾個參數,調用時就要傳幾個參數  # 參數一:1 參數二:2,這只是一個普通方法啦~  # 參數一:1 參數二:2,這只是一個普通方法啦~

利用pickle模組將對象序列化到本地

如單機遊戲的存檔(把對象的數據等資訊存儲到文件中,下次啟動再讀取回來) –> 遊戲擴展

import pickle      class Student:      def __init__(self, name):          self.name = name        def say_hi(self):          print("name:", self.name)        def save(self):          with open(self.name, "wb") as f:  # pickle 模組操作文件必須是b 模式              pickle.dump(self, f)  # 利用pickle 模組,將傳入的對象序列化到了文件中(json模組不支援對象這種類型)        @staticmethod      def get(name):          with open(name, "rb") as f:              obj = pickle.load(f)  # 利用pickle 模組,將文件中的對象反序列化成python中的對象              return obj      # 將rose 和 jack兩個從記憶體中對象序列化到文件中  stu = Student("rose")  stu.save()  stu2 = Student("jack")  stu2.save()    # 將他兩反序列化出來到記憶體中  obj = Student.get("rose")  # 調用類中的方法(類綁定方法)從文件中將對象載入到記憶體中  print(obj.name)  # 使用該對象獲取屬性值  # rose  obj2 = Student.get("jack")  print(obj2.name)  # jack    print(Student.__name__)  # 獲取類名  # Student    # 反序列化出來的對象和序列化的那個對象已經不是同一個對象了  print(id(stu), id(obj))  # 2161209937816 2161209971880  print(stu.name, obj.name)  # rose rose  print(id(stu2), id(obj2))  # 2161209937872 2161209971824  print(stu2.name, obj2.name)  # jack jack  obj2.name = 'jack2'  print(stu2.name, obj2.name)  # jack jack2

英雄大亂斗(隨機)案例

import random  import time      class Hero:      def __init__(self, name, health, attack, q_hurt, w_hurt, e_hurt):          lcs = locals()          lcs.pop('self')          self.__dict__.update(lcs)        def attack(self, enemy):          print(f"-- {self.name} --使用普通攻擊攻擊了-- {enemy.name} --,造成了 {self.attack} 點傷害,{enemy.name} 剩餘 {enemy.health} 點生命值。33[0m")          enemy.health -= self.attack        def Q(self, enemy):          print(f"33[0m-- {self.name} --使用Q技能攻擊了-- {enemy.name} --,造成了 {self.q_hurt} 點傷害,{enemy.name} 剩餘 {enemy.health} 點生命值。33[0m")          enemy.health -= self.q_hurt        def W(self, enemy):          print(f"33[32m-- {self.name} --使用W技能攻擊了-- {enemy.name} --,造成了 {self.w_hurt} 點傷害,{enemy.name} 剩餘 {enemy.health} 點生命值。33[0m")          enemy.health -= self.w_hurt        def E(self, enemy):          print(f"33[35m-- {self.name} --使用E技能攻擊了-- {enemy.name} --,造成了 {self.e_hurt} 點傷害,{enemy.name} 剩餘 {enemy.health} 點生命值。33[0m")          enemy.health -= self.e_hurt      def check_hero(enemy, team):      if enemy.health <= 0:          print(f"33[31m** {enemy.name} ** 陣亡。33[0m")          if team == 'blue':              blue_team.remove(enemy)          elif team == 'red':              red_team.remove(enemy)      def get_random_skill():      return skill_list.get(random.randint(1, 4))      def get_random_blue_hero():      return blue_team[random.randint(0, len(blue_team) - 1)]      def get_random_red_hero():      return red_team[random.randint(0, len(red_team) - 1)]      blue_team = [      Hero('瑞文', 465, 65, 30, 25, 70),      Hero('提莫', 300, 35, 50, 40, 60),  ]    red_team = [      Hero('李白', 320, 60, 35, 29, 77),      Hero('魯班', 280, 79, 35, 40, 80),  ]    skill_list = {      1: Hero.attack,      2: Hero.Q,      3: Hero.W,      4: Hero.E,  }      while len(red_team) > 0 and len(blue_team) > 0:      skill = get_random_skill()      blue = get_random_blue_hero()      red = get_random_red_hero()      flag = random.randint(0, 1)      if flag:          skill(blue, red)          check_hero(red, 'red')      else:          skill(red, blue)          check_hero(blue, 'blue')      time.sleep(0.3)        if len(red_team) == 0:          print(f"藍色方獲勝!")          print(f"藍色方所剩英雄狀態為:")          for hero in blue_team:              print(f"{hero.name} 剩餘生命值 {hero.health}")      elif len(blue_team) == 0:          print(f"紅色方獲勝!")          print(f"紅色方所剩英雄狀態為:")          for hero in red_team:              print(f"{hero.name} 剩餘生命值 {hero.health}")

注釋版

import random  import time      # 定義一個英雄類,表示英雄這一類的共同特徵  class Hero:      def __init__(self, name, health, attack, q_hurt, w_hurt, e_hurt):          lcs = locals()          lcs.pop('self')          self.__dict__.update(lcs)          '''              ********************************** 上述程式碼講解 *************************************              # 每次調用類生成對象的時候都會執行這裡面的程式碼,並將對象作為第一個參數self 傳進來              print(locals())              # {'e_hurt': 70, 'w_hurt': 25, 'q_hurt': 30, 'attack': 65, 'health': 465, 'name': '瑞文', 'self': <__main__.Hero object at 0x000002371823B278>}              lcs = locals()  # 這個locals()在 __init__ 函數里 可以獲取 __init__ 函數名稱空間里的那些名字,他是一個字典              lcs.pop('self')  # 發現上面的 locals() 多了一個 self 是不需要的,那就把它刪掉              print(lcs)              # {'e_hurt': 70, 'w_hurt': 25, 'q_hurt': 30, 'attack': 65, 'health': 465, 'name': '瑞文'}              # 這些內容正是初始化對象時想做的事(只不過是 對象.e_hurt = 70 這樣的形式而已)              self.__dict__.update(lcs)  # 將這些東西放到對象里,就重複了n變 self.參數 = 參數 (self.name = name)這樣的動作              print(self.__dict__)              # {'e_hurt': 70, 'w_hurt': 25, 'q_hurt': 30, 'attack': 65, 'health': 465, 'name': '瑞文'}                最初始的寫法:                  self.name = name                  self.health = health                  self.attack = attack                  self.q_hurt = q_hurt                  self.w_hurt = w_hurt                  self.e_hurt = e_hurt          '''        def attack(self, enemy):          enemy.health -= self.attack          print(f"-- {self.name} --使用普通攻擊攻擊了-- {enemy.name} --,造成了 {self.attack} 點傷害,{enemy.name} 剩餘 {enemy.health} 點生命值。33[0m")        def Q(self, enemy):          enemy.health -= self.q_hurt          print(f"33[0m-- {self.name} --使用Q技能攻擊了-- {enemy.name} --,造成了 {self.q_hurt} 點傷害,{enemy.name} 剩餘 {enemy.health} 點生命值。33[0m")        def W(self, enemy):          enemy.health -= self.w_hurt          print(f"33[32m-- {self.name} --使用W技能攻擊了-- {enemy.name} --,造成了 {self.w_hurt} 點傷害,{enemy.name} 剩餘 {enemy.health} 點生命值。33[0m")        def E(self, enemy):          enemy.health -= self.e_hurt          print(f"33[35m-- {self.name} --使用E技能攻擊了-- {enemy.name} --,造成了 {self.e_hurt} 點傷害,{enemy.name} 剩餘 {enemy.health} 點生命值。33[0m")      def check_hero(enemy, team):      if enemy.health <= 0:          # 33[31m 這種格式的是列印時的顏色控制(顏色可參考 https://www.cnblogs.com/easypython/p/9084426.html)          print(f"33[31m** {enemy.name} ** 陣亡。33[0m")          if team == 'blue':              blue_team.remove(enemy)          elif team == 'red':              red_team.remove(enemy)      # 隨機選擇一種攻擊方式  def get_random_skill():      # random_index = random.randint(1, 4)      # random_skill = skill_list.get(random_index)      # return random_skill  # 函數名當做返回值返回,拿到可以直接加括弧調用執行函數      return skill_list.get(random.randint(1, 4))  # 上面程式碼的簡便寫法      # 隨機選擇一個藍色方英雄  def get_random_blue_hero():      # 返回 blue_team 這個列表的索引為 random.randint(0, len(blue_team) - 1) 返回值的元素(英雄對象)      # return blue_team[random.randint(0, len(blue_team) - 1)]  # 下面幾行的簡便寫法      random_idndex = random.randint(0, len(blue_team) - 1)      hero = blue_team[random_idndex]      return hero      # 隨機選擇一個紅色方英雄  def get_random_red_hero():      return red_team[random.randint(0, len(red_team) - 1)]      # 藍色方英雄陣容 --- 可自定義 ---  # 方便隨機數取英雄對象  blue_team = [      # 英雄名 生命值 普通攻擊力 Q技能傷害 W技能傷害 E技能傷害      #  瑞文   465      65       30        25        70      Hero('瑞文', 465, 65, 30, 25, 70),      Hero('提莫', 300, 35, 50, 40, 60),      Hero('錘石', 600, 15, 20, 0, 32),  ]    # 紅色方英雄陣容 --- 可自定義 ---  # 方便隨機數取英雄對象  red_team = [      Hero('李白', 320, 60, 35, 29, 77),      Hero('魯班', 280, 79, 35, 40, 80),      Hero('盾山', 800, 3, 3, 3, 3),  ]    # 技能數字對應表(方便根據隨機數取技能)  skill_list = {      1: Hero.attack,      2: Hero.Q,      3: Hero.W,      4: Hero.E,  }      def run():      while len(red_team) > 0 and len(blue_team) > 0:          # 調用方法隨機獲得一個技能          skill = get_random_skill()          # 調用方法隨機獲得一個藍色方英雄          blue = get_random_blue_hero()          # 調用方法隨機獲得一個紅色方英雄          red = get_random_red_hero()          # 隨機選擇一方為攻擊方(那麼另一方就是被攻擊方)          flag = random.randint(0, 1)          if flag:              skill(blue, red)              check_hero(red, 'red')          else:              skill(red, blue)              check_hero(blue, 'blue')          # 暫停0.3秒,可以慢慢看戰鬥過程          time.sleep(0.3)            # 如果有任意一方沒有英雄了,即遊戲結束          if len(red_team) == 0:              print(f"藍色方獲勝!")              print(f"藍色方所剩英雄狀態為:")              for hero in blue_team:                  print(f"{hero.name} 剩餘生命值 {hero.health}")          elif len(blue_team) == 0:              print(f"紅色方獲勝!")              print(f"紅色方所剩英雄狀態為:")              for hero in red_team:                  print(f"{hero.name} 剩餘生命值 {hero.health}")      if __name__ == '__main__':      run()      '''          戰鬥記錄          ************************** 省略n多中間戰鬥步驟  *********************************          -- 錘石 --使用W技能攻擊了-- 盾山 --,造成了 0 點傷害,盾山 剩餘 42 點生命值。          -- 盾山 --使用E技能攻擊了-- 瑞文 --,造成了 3 點傷害,瑞文 剩餘 289 點生命值。          -- 瑞文 --使用E技能攻擊了-- 盾山 --,造成了 70 點傷害,盾山 剩餘 -28 點生命值。          ** 盾山 ** 陣亡。          藍色方獲勝!          藍色方所剩英雄狀態為:          瑞文 剩餘生命值 289          錘石 剩餘生命值 235            戰鬥記錄2          ************************** 省略n多中間戰鬥步驟  *********************************          -- 盾山 --使用普通攻擊攻擊了-- 錘石 --,造成了 3 點傷害,錘石 剩餘 11 點生命值。          -- 錘石 --使用普通攻擊攻擊了-- 盾山 --,造成了 15 點傷害,盾山 剩餘 288 點生命值。          -- 盾山 --使用E技能攻擊了-- 瑞文 --,造成了 3 點傷害,瑞文 剩餘 -1 點生命值。          ** 瑞文 ** 陣亡。          -- 盾山 --使用普通攻擊攻擊了-- 錘石 --,造成了 3 點傷害,錘石 剩餘 8 點生命值。          -- 盾山 --使用普通攻擊攻擊了-- 錘石 --,造成了 3 點傷害,錘石 剩餘 5 點生命值。          -- 盾山 --使用W技能攻擊了-- 錘石 --,造成了 3 點傷害,錘石 剩餘 2 點生命值。          -- 盾山 --使用Q技能攻擊了-- 錘石 --,造成了 3 點傷害,錘石 剩餘 -1 點生命值。          ** 錘石 ** 陣亡。          紅色方獲勝!          紅色方所剩英雄狀態為:          盾山 剩餘生命值 288      '''    '''  有紅藍兩方英雄(可自定義個數)      隨機一方英雄使用隨機攻擊方式攻擊另一方英雄,任意一方英雄全部陣亡則遊戲結束          每個英雄有 名字、生命值、普通攻擊、Q技能攻擊、W技能攻擊、E技能攻擊以及對應的傷害值              當生命值為 0 時陣亡,不再參與戰鬥  '''

後續完善部落格思路

調用類生成對象發生的一些事情(對比變數、模組名稱空間生成等)    屬性的查找順序(畫圖表示吧)    先找自己的,再找父類的,一級一級往上找,直到基類object,再沒有報錯    英雄大亂斗案例  序列化、反序列化對象(保存、讀取對象)(遊戲退出,讀檔)