[ python ] 初始面向對象

首先,經過以前學習的函數編寫一個 人狗大戰 的例子。python

分析下這個需求,人 狗 大戰  三個事情。
角色:人、狗
動做:狗咬人,人打狗編程

 

先建立人和狗兩個角色:bash

def person(name, hp, aggr, sex):
    data = {
        'name': name,
        'hp': hp,
        'aggr': aggr,
        'sex': sex
    }

    return data


def dog(name, hp, aggr, dog_type):
    data = {
        'name': name,
        'hp': hp,
        'aggr': aggr,
        'dog_type': dog_type
    }

    return data


kk = person('kk', 100, 5, 'male')    # 人的角色
gg = dog('gg', 100, 10, 'teddy')    # 狗的角色
人和狗兩個角色

 

 

人建立完成,可是咱們還有兩個動做才能開始遊戲,因而使用函數在寫兩個動做:ide

def person(name, hp, aggr, sex):
    data = {
        'name': name,
        'hp': hp,
        'aggr': aggr,
        'sex': sex
    }

    return data


def dog(name, hp, aggr, dog_type):
    data = {
        'name': name,
        'hp': hp,
        'aggr': aggr,
        'dog_type': dog_type
    }

    return data


kk = person('', 100, 5, 'male')
gg = dog('狗狗', 100, 10, 'teddy')



def bite(g, p):
    p['hp'] -= g['aggr']
    print('%s 被咬,掉了%s 的血。' %(p['name'], g['aggr']))

bite(gg, kk)

def hit(p, g):
    g['hp'] -= p['aggr']
    print('%s 被打,掉了%s 的血。' %(g['name'], p['aggr']))

hit(kk, gg)
兩個動做

 

 

上面的代碼已經實現了咱們最初設計的人狗大戰,可是每一個函數都是相互獨立的,沒有任何限制。也就是說,能夠出現如下這種狀況:函數

hit(gg, kk)
bite(kk, gg)

執行結果:

人 被打,掉了10 的血。
狗狗 被咬,掉了5 的血。

 

 

這樣,人和狗正好相反了,應該是人打狗,狗咬人才對。所以必需要加上限制:學習

def person(name, hp, aggr, sex):
    data = {
        'name': name,
        'hp': hp,
        'aggr': aggr,
        'sex': sex
    }

    def hit(g):
        g['hp'] -= data['aggr']
        print('%s 被打,掉了%s 的血。' % (g['name'], data['aggr']))

    data['hit'] = hit
    return data


def dog(name, hp, aggr, dog_type):
    data = {
        'name': name,
        'hp': hp,
        'aggr': aggr,
        'dog_type': dog_type
    }

    def bite(p):
        p['hp'] -= data['aggr']
        print('%s 被咬,掉了%s 的血。' % (p['name'], data['aggr']))

    data['bite'] = bite
    return data


kk = person('', 100, 5, 'male')
gg = dog('狗狗', 100, 10, 'teddy')

kk['hit'](gg)
gg['bite'](kk)
爲角色的動做加上限制

 

 

這樣,咱們在代碼層面就實現了限制,代碼基本完美了。spa

 

回看咱們上面的代碼,建立的是角色函數,也就是經過角色函數,咱們能夠建立無數的人和狗大戰。設計

人是人類、狗是狗類 經過這樣的思想來進行編程就是面向對象的編程思想。從角色和大類入手,上帝視角

好比:
人類,是一個大類,這個大類裏面有各類各樣的屬性,好比吃飯,睡覺,打豆豆這都是共性。
類中還有方法,方法就是一個過程,一個動做,作某件事。
好比:登山、打籃球。這些都是動做,都應該是一個方法出現;3d

 

面向過程與面向對象

面向過程的程序設計核心是過程。過程即解決問題的步驟,面向過程的設計就比如精心設計好一條流水線。

優勢:極大的下降了寫程序的複雜度,只須要順着要執行的步驟,堆疊代碼便可;
缺點:一套流水線或者流程就是用來解決一個問題,代碼牽一髮而動全身。

應用場景:通常 bash 腳本都是面向過程思想寫出來的,處理流程化事件。


面向對象的程序設計

面向對象的程序設計的核心是對象。

優勢:解決了程序的擴展性。對某一個對象單獨修改,會馬上反映到整個體系中,如對遊戲中一我的物參數的特徵和技能修改都很容易。
缺點:可控性差,沒法像面向過程的程序設計流水線式的能夠很精準的預測問題的處理流程與結果,面向對象的程序一旦開始就由對象之間交互解決問題。

應用場景:需求常常變化的軟件,通常需求的變化都集中在用戶層,互聯網應用,企業內部軟件,遊戲等都是面向對象的程序設計大顯身手的地方;

在python中面向對象的程序設計並非所有。

面向對象編程可使程序的維護和擴展變得更簡單,而且能夠大大提升程序開發效率,基於面向對象的程序可使它人更加容易理解你的代碼邏輯。
雖然 面向對象很好用,可是它並無比面向過程高級,對於不一樣的應用需求場景採用合適的編程思想纔是最重要的。code

 

def functionName(args):
    函數體
申明函數
class Data:
    pass
申明類

 

 

類有兩種做用:屬性引用和實例化

屬性引用(類名.屬性)

class Person:
    role = 'person'
    
    def walk(self):
        print('person is walking...')

 上面代碼中 role 是 Person的一個屬性,walk 是 Person的方法。

 

print(Person.role)  # 查看人的role屬性
print(Person.walk)  # 引用人的走路方法,注意,這裏不是在調用

 

 

實例化:類名加括號就是實例化,會自動觸發 __init__ 函數的運行,能夠用它來爲每一個實例定製本身的特徵

class Person:
    def __init__(self, name):
        self.name = name


p = Person('hkey')  # 實例化 Person
print(p.name)

# 執行結果:
# hkey


p = Person('hkey') 就是一個實例化的過程,實例化會自動執行 __init__()方法。

 

 

關於 self

self: 在實例化時自動將對象/實例自己傳給__init__的第一個參數
class Person:
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex
        print(id(self))
        
        
p = Person('hkey', 20, 'male')  # 實例化 Person
print(id(p))

# 執行結果:
# 2074449353472
# 2074449353472

經過上面的代碼,咱們能夠查看到 self 和 對象 p 內存空間地址是一致的,印證了上面這句話。

如何查看一個類有哪些屬性和方法,可使用__dict__方法

class Person:
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex


print(Person.__dict__)
p = Person('hkey', 20, 'male')  # 實例化 Person
print(p.__dict__)

 

 

對象的相關知識

對象是關於類而實際存在的一個例子,即實例
對象/實例只有一種做用:屬性引用

class Person:
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

p = Person('hkey', 20, 'male')  # 這一步就是實例化一個對象p



class Person:
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex


p = Person('hkey', 20, 'male')  # 實例化 Person

print('name:', p.name)
print('age:', p.age)
print('sex:', p.sex)
print('walk:', p.walk)    # 在類中,方法也是對象。

# 執行結果:

# name: hkey
# age: 20
# sex: male
# walk: <bound method Person.walk of <__main__.Person object at 0x0000024A4E819400>>
對象的使用

 

 

這裏,咱們把以前人狗大戰的例子經過面向對象來重寫下:

class Person(object):
    def __init__(self, name, hp, aggr, job):
        self.name = name
        self.hp = hp
        self.aggr = aggr
        self.job = job

    def hit(self, gg):
        gg.hp -= self.aggr
        print('\033[31;1m%s被打,掉了%s的血。\033[0m' % (gg.name, self.aggr))


class Dog(object):
    def __init__(self, name, hp, aggr, kind):
        self.name = name
        self.hp = hp
        self.aggr = aggr
        self.kind = kind

    def bite(self, p):
        p.hp -= self.aggr
        print('\033[31;1m%s被咬,掉了%s的血。\033[0m' % (p.name, self.aggr))


p = Person('kk', 100, 2, 'it')
teddy = Dog('teddy', 100, 3, 'teddy')

p.hit(teddy)
print(teddy.hp)

teddy.bite(p)
print(p.hp)
人狗大戰

 

 

能夠分析下上面的代碼。
1. 咱們建立兩個類,一我的類,一個狗類
2. 經過實例化,咱們建立了兩個對象, p 和 teddy
3. 經過p.hit 調用人類的方法時,參數爲狗類的對象,這裏就是用到了對象的交互。
4. 經過teddy.bite 調用狗類的方法時,參數爲人類的對象, 這裏就是用到了對象的交互。

 

因此說,面向對象程序一旦開始就由對象之間的交互解決問題。

 

實例化:
    對象 = 類名(參數是__init__方法的參數)

實例 = 對象 徹底沒區別

對象查看屬性:
    對象.屬性名
    
對象調用方法:
    對象.方法名(參數)

 

練習:正方形的周長和麪積

class Squ:
    def __init__(self, length):
        self.length = length

    def per(self):
        return self.length * 4

    def area(self):
        return self.length ** 2


cfx = Squ(20)
print(cfx.per())
print(cfx.area())
正方形的周長和麪積

 

 

類命名空間與對象、實例的命名空間

建立一個類就會建立一個類的名稱空間用來存儲類中定義的全部名字,這些名字稱爲類的屬性

而類有兩種屬性:靜態屬性和動態屬性

  •     靜態屬性就是直接在類中定義的變量
  •     動態屬性就是定義在類中的方法

 

class Person:
    language = 'Chinese'
    
    def __init__(self, name, age, job):
        self.name = name
        self.age = age
        self.job = job

hkey = Person('hkey', 20, 'it')
jay = Person('jay', 20, 'singer')

 

 

上面的代碼中有一個類,實例化出兩個對象 hkey 和 jay, 以下圖:

 

1. 對象是經過類實例化出來的;
2. 對象和類是單向聯繫,也就是說,經過對象可以找到類,可是經過類是沒法尋找到對象的;
3. 對象共享類中的屬性和方法,可是兩者之間是相互獨立的內存空間

 

class Person:
    language = 'Chinese'

    def __init__(self, name, age, job):
        self.name = name
        self.age = age
        self.job = job


hkey = Person('hkey', 20, 'it')
jay = Person('jay', 20, 'singer')

print(Person.language)    # 經過類調用靜態屬性
print(hkey.language)    # 經過對象 hkey 調用靜態屬性
print(jay.language)        # 經過對象 jay 調用靜態屬性

# 執行結果:
# Chinese
# Chinese
# Chinese

 

 

1. 經過類名調用靜態屬性,由於靜態屬性就在類的命名空間中,直接就能夠取出使用;
2. 經過對象調用靜態屬性,首先對象會先在本身的命名空間中尋找 language 屬性,若是沒有會在類中去尋找 language 類中有則返回
3. 當對象自定義和類中靜態屬性同樣的名稱時,對象再次調用時,由於本身命名空間中已經存在,則直接返回。

class Person:
    language = 'Chinese'

    def __init__(self, name, age, job):
        self.name = name
        self.age = age
        self.job = job


hkey = Person('hkey', 20, 'it')
jay = Person('jay', 20, 'singer')

print(Person.language)
hkey.language = 'English'
print(hkey.language)
print(jay.language)

# 執行結果:
# Chinese
# English
# Chinese

 

 

因此,在使用類中靜態屬性的時候,最好使用 類名.靜態屬性 調用

 

類中靜態屬性使用的經典例子:

要求:建立一個類,每次實例化一個對象就記錄下來。

class Count:
    count = 0
    def __init__(self):
        Count.count += 1
a = Count()
b = Count()
print(a.count)
記錄每次實例化
相關文章
相關標籤/搜索