1. 程式人生 > >day 22 - 1 面向物件

day 22 - 1 面向物件

面向物件

字典實現人狗大戰

#定義角色
def Person(name,hp,aggr,sex):
    person = {
        'name':name,
        'hp':hp,
        'aggr':aggr,
        'sex':sex
        }
    return person


def Dog(name,hp,aggr,kind):
    dog = {
        'name':name,
        'hp':hp,
        'aggr':aggr,
        'kind':kind
        }
    
return dog
#定義技能
#
def attack(person,dog):
    dog['hp'] -= person['aggr']
    print('%s損失了%s的血量'%(dog['name'],person['aggr']))

#
def bite(dog,person):
    person['hp'] -= dog['aggr']
    print('%s損失了%s的血量'%(person['name'],dog['aggr']))
#print(Person('new',100,2,'不祥'))
#print(Dog('二哈',100,3,'taddy'))
man = Person('雷諾',100,2,'不祥') #例項化 dogs = Dog('二哈',100,3,'taddy') bite(dogs,man) print(man)

這樣會出現一個問題,就是把角色搞混

我們把技能封裝到任務所屬的函式中,這個就不容易把任務關係搞混了

def Person(name,hp,aggr,sex):
    person = {
        'name':name,
        'hp':hp,
        'aggr':aggr,
        'sex':sex
        }
    def attack(dog):
        dog[
'hp'] -= person['aggr'] print('%s損失了%s的血量'%(dog['name'],person['aggr'])) person['attack'] = attack return person def Dog(name,hp,aggr,kind): dog = { 'name':name, 'hp':hp, 'aggr':aggr, 'kind':kind } def bite(person): person['hp'] -= dog['aggr'] print('%s損失了%s的血量'%(person['name'],dog['aggr'])) dog['bite'] = bite return dog man = Person('new',100,2,'不祥') dogs = Dog('二哈',100,3,'taddy') man['attack'](dogs) #然後我們就可以這樣來呼叫 Person 函式中的 attack 函式 dogs['bite'](man)

簡單小結:

Dog 函式和 Person 函式 都是定義了一類事物
直到呼叫了函式,賦值了之後才真的有了一個實實在在的人或狗
程式碼精簡了 方便增加人物 方便修改 人物更加規範 —— 人模子

 

面向物件程式設計
所謂模子 就是 類 抽象的 我能知道有什麼屬性 有什麼技能 但不能知道屬性具體的值
人 屋子  就是物件   有具體的值,屬性和技能都是根據類規範的

面向過程 VS 面向物件

面向過程的程式設計的核心是過程(流水線式思維)
  優點是:極大的降低了寫程式的複雜度,只需要順著要執行的步驟,堆疊程式碼即可
  缺點是:一套流水線或者流程就是用來解決一個問題,程式碼牽一髮而動全身。
  應用場景:一旦完成基本很少改變的場景,著名的例子有 Linux 核心,git,以及Apache HTTP Server等

面向物件的程式設計的
  優點是:解決了程式的擴充套件性。對某一個物件單獨修改,會立刻反映到整個體系中,如對遊戲中一個人物引數的特徵和技能修改都很容易。
  缺點:可控性差,無法像面向過程的程式設計流水線式的可以很精準的預測問題的處理流程與結果,面向物件的程式一旦開始就由物件之間的互動解決問題,即便是上帝也無法預測最終結果。於是我們經常看到一個遊戲人某一引數的修改極有可能導致陰霸的技能出現,一刀砍死3個人,這個遊戲就失去平衡。
  應用場景:需求經常變化的軟體,一般需求的變化都集中在使用者層,網際網路應用,企業內部軟體,遊戲等都是面向物件的程式設計大顯身手的好地方

 

自定義類

#定義
class 類名:
    屬性 = 'a'

#檢視
print(類名.屬性)

# 類名的作用 就是操作屬性 檢視屬性

我們來看一個例子

class Person:                   # 類名
    def __init__(solf,*args):   # 初始化方法,self是物件,是一個必須傳的引數 
        solf.name = args[0]     # self 就是一個可以儲存很多屬性的大字典
        solf.hp = args[1]       # 而往字典裡新增屬性的方式發生了一些變化
        solf.aggr = args[2]
        solf.sex = args[3]
per = Person('小強',100,3,'不祥')
print(per)  #返回的是一個記憶體地址

print(per.name)  #檢視屬性值
print(per.hp)    #檢視屬性值
print(per.aggr)  #檢視屬性值

 

呼叫類中的方法

#呼叫類中的方法
class Person:
    count = 'China'          # 創造了一個只要是這個類就一定有的屬性,這個是類擁有的 而不是屬性
                             # 類屬性 靜態屬性
    def __init__(self,*args):# 初始化方法
        self.name = args[0]
        self.hp = args[1]
        self.aggr = args[2]
        self.sex = args[3]
    def run(self,n):          #定義了一個方法,一般情況下必須傳 self 引數,且必須寫在第一個
                              #後面還可以傳其他引數,是自由的
        print('%s跑跑跑,跑了%s公里'%(self.name,n))  ##2.接收引數
per = Person('小強',100,3,'不祥')

print(Person.__dict__)  #可以看到 Person 方法中有 run 這個函式(#檢視所有屬性)
print(Person.run)       #為一個記憶體地址
Person.run(per,6)       #此處為什麼是 per,因為在賦值使用 Person 函式後 self 的值返回給了 per

#per.run()        #另一種簡便方法  物件名 + 方法名  與 Person.run(per) 等價
per.run(5)        ##1.傳值
print(per.count)  #獲取靜態屬性

類的內容檢視、修改、新增

#接上
#對類的內容檢視、修改、新增
print(Person.__dict__)  #得到的是類中儲存的所有名字
print(Person.__dict__['count']) #可以通過 __dict__ 使用字典的方式操作

print(per.__dict__)     #得到的 per 所有屬性
print(per.__dict__['name']) 
per.__dict__['name'] = '小吼' #可以檢視也可以修改
print(per.__dict__['name'])

print(per.name)
per.name = '鳥人'     #不過一般通過屬性來修改
print(per.name)
per.age = 49          #增加
print(per.__dict__)

 

簡單小結:

物件 = 類名()
過程:
  類名() 首先 會創造出一個物件,建立了一個self變數
  呼叫 init 方法,類名括號裡的引數會被這裡接收
  執行 init 方法
  返回 self

物件能做的事:
  檢視屬性
  呼叫方法
  __dict__ 對於物件的增刪改查操作都可以通過字典的語法進行

類名能做的事:
  例項化
  呼叫方法 : 只不過要自己傳遞 self 引數
  呼叫類中的屬性,也就是呼叫靜態屬性
  __dict__ 對於類中的名字只能看 不能操作 比如:修改 count,報錯

 

接著我要切入主題了

使用類來完成我們最初的遊戲:人狗大戰

#大致如下
class Person:
    def __init__(self,name,hp,aggr,sex):
        self.name = name
        self.hp = hp
        self.aggr = aggr
        self.sex =sex
    def attack(self,dog):
        dog.hp -= self.aggr
        print('%s 損失了 %s 點 hp'%(dog.name,self.aggr))
class Dog:
    def __init__(self,name,hp,aggr,kind):
        self.name = name
        self.hp = hp
        self.aggr = aggr
        self.kind = kind
    def bite(self,person):
        person.hp -= self.aggr
        self.hp -= person.aggr
        print('%s 損失了 %s 點 hp'%(person.name,self.aggr))
        if person.hp < 0:
            print('%s 失血過多戰敗,%s 剩餘 %s 點 HP'%(person.name,self.name,self.hp))
        else:
            print('%s 此回合戰勝%s,剩餘 %s 點 hp,%s 剩餘%s 點 HP'%(person.name,self.name,person.hp,self.name,self.hp))

per = Person('雷諾',100,23,'')
dog = Dog('異蟲',200,12,'未知',)

while 1:
    dog.bite(per)
    if per.hp < 0 or dog.hp < 0:
        break

流程
  定義類
  init 方法
  self 是什麼 self擁有屬性都屬於物件
  類中可以定義靜態屬性
  類中可以定義方法,方法都有一個必須傳的引數 self
  例項化
  例項、物件
  物件檢視屬性
  物件呼叫方法

 

小結:

定義類
  class
  函式 : 方法 動態屬性 # 類中可以定義方法,方法都有一個必須傳的引數 self
  變數 : 類屬性 靜態屬性 # 類中可以定義靜態屬性
__init__ 方法 初始化方法
python 幫我們建立了一個物件 self
  每當我們呼叫類的時候就會自動觸發這個方法。預設傳 self
  在 init 方法裡面可以對 self 進行賦值
self 是什麼 self 擁有屬性都屬於物件
  在類的內部,self 就是一個物件
  alex = Person()
  alex.walk == Person.walk(alex)
例項化
  物件 = 類(引數是 init 方法的)
例項、物件 完全沒有區別
物件檢視屬性
  物件.屬性名
物件呼叫方法
  物件.方法名(引數) #類名.方法名(物件名,引數)