面向對象編程進階

前言

我們在了解面向對象的入門知識,知道如何定義一個類和對象的時候,我們應該向它更深的知識進行拓展。

@property 裝飾器

它的功能就是將一個隱喻的屬性進行包裝,該屬性是設計者不希望使用者直接訪問該屬性,這個時候就使用裝飾器@property。例如:

class Person(object):
    def __init__(self, name, age):
        self._name = name
        self._age = age

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name):
        self._name = name

    # getter - 訪問器
    @property
    def age(self):
        return self._age

    # setter - 修改器
    @age.setter
    def age(self, age):
        self._age = age if 20 < age < 60 else 30

    def watch_av(self):
        if self._age >= 18:
            print('看片')
        else:
            print('看動漫')

slots魔法

slots可以限定當前的類中的屬性的個數(shù),需要注意的是它只能限定該類的對象并不能限定其子類。例如:

class Student(object):
    #  __slots__魔法的使用
    __slots__ = ('_name', '_age')

    def __init__(self, name, age):
        self._name = name
        self._age = age

    @property   # 屬性訪問器
    def age(self):
        return self._age

    @age.setter  # 屬性修改器
    def age(self, age):
        self._age = age if 15 < age < 25 else 20

    def watch_av(self):
        if self._age >= 18:
            print('看片')
        else:
            print('看動漫')

靜態(tài)方法和類方法

所謂的靜態(tài)方法就是一個方法是屬于那一個類而不屬于該對象,關鍵字@staticmethod,類方法就是對象所擁有的某些行為。

class Tr(object):

    def __init__(self, a, b, c):
        self._a = a
        self._b = b
        self._c = c

    @property
    def a(self):
        return self._a

    @property
    def b(self):
        return self._b

    @property
    def c(self):
        return self._c

    # 判斷是不是三角形
    @staticmethod
    def is_tr(a, b, c):
        return a + b > c and a + c > b and b + c > a

    def perimer(self):
        return self._a + self._b + self._c

def main():
    a = 10
    b = 10
    c = 12
    if Tr.is_tr(a, b, c):
        tr = Tr(a, b, c)
        print('周長是:%d' % tr.perimer())

if __name__ == '__main__':
    main()

和在類中定義靜態(tài)的方法一樣,我們也可以在類中定義類關鍵字@classmethon 例如:

沒有在類中定義類的時候:
import time


class Rectangle:

    def __init__(self, width, height):
        self._width = width
        self._height = height

    def perimeter(self):
        return (self._width + self._height) * 2

    def area(self):
        return self._height * self._width


class Clock(object):
    local_time = time.localtime()
    get_time = list(local_time)

    def __init__(self, hour=get_time[3], minute=get_time[4], second=get_time[5]):
        # 不要參數(shù) 使用系統(tǒng)時間  python中的time模塊
        self._hour = hour
        self._minute = minute
        self._second = second

    def run(self):
        self._second += 1
        if self._second == 60:
            self._minute += 1
            self._second = 0
            if self._minute == 60:
                self._minute =0
                self._hour += 1
                if self._hour == 24:
                    self._hour =0

    def show(self):
        return '%02d:%02d:%02d' % (self._hour, self._minute, self._second)

    # 下面的方法可以獲得對象的字符串表示形式
    # 當我們用print打印對象時候會自動調用該方法
    # def __str__(self):
    #     return '%02d:%02d:%02d' % (self._hour, self._minute, self._second)


def main():
    clock = Clock()
    while True:
        print(clock.show())
        clock.run()
        time.sleep(1)


if __name__ == '__main__':
    main()

使用了之后:

from time import time, localtime, sleep


class Clock(object):
    """數(shù)字時鐘"""

    def __init__(self, hour=0, minute=0, second=0):
        self._hour = hour
        self._minute = minute
        self._second = second

    @classmethod
    def now(cls):
        ctime = localtime(time())
        return cls(ctime.tm_hour, ctime.tm_min, ctime.tm_sec)

    def run(self):
        """走字"""
        self._second += 1
        if self._second == 60:
            self._second = 0
            self._minute += 1
            if self._minute == 60:
                self._minute = 0
                self._hour += 1
                if self._hour == 24:
                    self._hour = 0

    def show(self):
        """顯示時間"""
        return '%02d:%02d:%02d' % \
               (self._hour, self._minute, self._second)


def main():
    # 通過類方法創(chuàng)建對象并獲取系統(tǒng)時間
    clock = Clock.now()
    while True:
        print(clock.show())
        sleep(1)
        clock.run()


if __name__ == '__main__':
    main()

類之間的關系有如下:

類和類之間的關系有三種:is-a, has-a, use-a
is-a : 簡單說就是一個繼承關系,比如學生和人類,老鼠和動物。
has-a : 是一種強關聯(lián)的關系,比如汽車和輪子,4
use-a :是一種依賴關系,比如人撞墻,人使用了墻,否則無墻可撞。


20180313194509293.png

繼承和多態(tài)

何為繼承,就是一個類從另外的一個類中得到該類的屬性和方法就稱之為繼承。得到屬性和方法的就叫做子類,提供屬性和方法的就叫做父類。子類之中除了父類之中的那些東西之外還可以添加自己需要的方法和屬性。當子類繼承父類的方法的時候可以重新修改該方法,這就稱之為多態(tài)
繼承:

# 繼承-- 從已經有的類創(chuàng)建新類的過程
# 提供繼承信息的稱為父類(超類/基類)
# 得到繼承信息的稱為子類(派生類/衍生類)
# 通過繼承我們可以將子類中的重復代碼抽取到父類中
# 子類通過繼承并復用這些代碼來減少重復代碼的編寫
# 將來如果要維護子類的公共代碼只需要在父類中進行操作即可
# has - a 關聯(lián)關系  (人和手)
# use - a 依賴關系  (人和房子)
# is - a  繼承關系  (老師和人類,學生和人類)
# 任何時候子類可以替換掉父類


class Person(object):
    """人"""

    def __init__(self, name, age):
        self._name = name
        self._age = age

    @property
    def name(self):
        return self._name

    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, age):
        self._age = age

    def play(self):
        print('%s正在愉快的玩耍.' % self._name)

    def watch_av(self):
        if self._age >= 18:
            print('%s正在觀看愛情動作片.' % self._name)
        else:
            print('%s只能觀看《熊出沒》.' % self._name)


class Student(Person):
    """學生"""

    def __init__(self, name, age, grade):
        super().__init__(name, age)
        self._grade = grade

    @property
    def grade(self):
        return self._grade

    @grade.setter
    def grade(self, grade):
        self._grade = grade

    def study(self, course):
        print('%s的%s正在學習%s.' % (self._grade, self._name, course))


class Teacher(Person):
    """老師"""

    def __init__(self, name, age, title):
        super().__init__(name, age)
        self._title = title

    @property
    def title(self):
        return self._title

    @title.setter
    def title(self, title):
        self._title = title

    def teach(self, course):
        print('%s%s正在講%s.' % (self._name, self._title, course))


def main():
    stu = Student('王大錘', 15, '初三')
    stu.study('數(shù)學')
    stu.watch_av()
    t = Teacher('mr.l', 26, '博士')
    t.teach('人體學')
    t.watch_av()


if __name__ == '__main__':
    main()

多態(tài):

from abc import ABCMeta, abstractmethod


class Pet(object, metaclass=ABCMeta):
    """寵物"""

    def __init__(self, nickname):
        self._nickname = nickname

    @abstractmethod
    def make_voice(self):
        """發(fā)出聲音"""
        pass


class Dog(Pet):
    """狗"""

    def make_voice(self):
        print('%s: 汪汪汪...' % self._nickname)


class Cat(Pet):
    """貓"""

    def make_voice(self):
        print('%s: 喵...喵...' % self._nickname)


def main():
    pets = [Dog('旺財'), Cat('凱蒂'), Dog('大黃')]
    for pet in pets:
        pet.make_voice()


if __name__ == '__main__':
    main()

上面代碼中的Pet是一個抽象類,不能直接使用它來創(chuàng)建一個對象,但是可以使用子類來繼承它,在子類繼承它的時候必須繼承該抽象類的抽象方法,

綜合案例

1 奧特曼打小怪獸

from random import randint


class Ultraman(object):

    __slots__ = ('_name', '_hp', '_mp')  # 限定當前這個類里面只有這三個字段

    def __init__(self, name, hp, mp):
        self._name = name
        self._hp = hp
        self._mp = mp

    @property
    def name(self):
        return self._name

    @property
    def hp(self):
        return self._hp

    @hp.setter
    def hp(self, hp):
        self._hp = hp if hp > 0 else 0

    @property
    def mp(self):
        return self._mp

    @mp.setter
    def mp(self, mp):
        self._mp = mp if mp >= 0 else 0

    def attack(self, monster):
        injury = randint(15, 25)
        monster.hp -= injury

    def huge_attack(self, monster):
        if self._mp >= 50:
            self._mp -= 50
            injury = monster.hp * 3 // 4
            injury = injury if injury >= 50 else 50
            monster.hp -= injury
        else:
            self.attack(monster)

    def magic_attack(self, monsters):
        if self.mp >= 20:
            self.mp -= 20
            for monster in monsters:
                monster.hp -= randint(10, 15)

    def __str__(self):
        return '%s奧特曼\n' % self._name + \
            '生命值: %d\n' % self._hp + \
            '魔法值: %d\n' % self._mp


class Monster(object):

    __slots__ = ('_name', '_hp')

    def __init__(self, name, hp):
        self._name = name
        self._hp = hp

    @property
    def name(self):
        return self._name

    @property
    def hp(self):
        return self._hp

    @hp.setter
    def hp(self, hp):
        self._hp = hp if hp >=0 else 0

    def attack(self, ultraman):
        injury = randint(10, 20)
        ultraman.hp -= injury

    def __str__(self):
        return '%s怪獸\n' % self.name + \
                '生命值: %d\n' % self.hp


def main():
    u = Ultraman('駱昊', 1000, 500)
    print(u)
    m1 = Monster('舒玲1', 250)
    m2 = Monster('舒玲2', 250)
    m3 = Monster('舒玲3', 250)
    ms = [m1, m2, m3]
    for val in ms:
        print(val, end=' ')
    attack_round = 1
    while u.hp > 0 and (m1.hp + m2.hp + m3.hp) > 0:
        print('====第%d回合====' % attack_round)
        a = randint(1, 10)
        b = randint(0, 2)
        if a <= 6:
            while ms[b].hp <= 0:
                b = randint(0, 2)
            u.attack(ms[b])
        elif 6 < a <= 9:
            u.magic_attack(ms)
        else:
            u.huge_attack(ms[b])
        for index in range(len(ms)):
            if ms[index].hp > 0:
                ms[index].attack(u)
        print(u)
        for val in ms:
            print(val, end=' ')
        attack_round += 1
    if u.hp > 0:
        print('%s奧 特曼勝利' % u.name)
    else:
        print('小怪獸獲勝')


if __name__ == '__main__':
    main()

2 Puke

from random import randrange


class Card(object):
    """一張牌"""
    def __init__(self, suite, face):
        self._suite = suite
        self._face = face

    @property
    def face(self):
        return self._face

    @property
    def suite(self):
        return self._suite

    def __str__(self):
        if self._face == 1:
            face_str = 'A'
        elif self._face == 11:
            face_str = 'J'
        elif self._face == 12:
            face_str = 'Q'
        elif self._face == 13:
            face_str = 'K'
        else:
            face_str = str(self._face)
        return '%s%s' % (self._suite, face_str)


class Poker(object):
    """一副牌"""
    def __init__(self):
        self._cards = []
        self._current = 0
        for suite in '????':
            for face in range(1, 14):
                card = Card(suite, face)
                self._cards.append(card)

    @property
    def cards(self):
        return self._cards

    def shuffle(self):
        """洗牌"""
        self._current = 0
        cards_len = len(self._cards)
        for index in range(cards_len):
            pos = randrange(cards_len)
            self._cards[index], self.cards[pos] = \
                self._cards[pos], self.cards[index]

    # 使用屬性一般需要返回一個值
    @property
    def next(self):
        """發(fā)牌"""
        card = self.cards[self._current]
        self._current += 1
        return card

    @property
    def has_next(self):
        """還有沒有牌"""
        return self._current < len(self._cards)


class Player(object):

    def __init__(self, name):
        self._name = name
        self._cards_on_hand = []

    @property
    def name(self):
        return self._name

    @property
    def cards_on_hand(self):
        return self._cards_on_hand

    # 得到卡片
    def get(self, card):
        self._cards_on_hand.append(card)

    # 排序
    def arrange(self):
        self._cards_on_hand.sort(key=get_key)

    # 點數(shù)計數(shù)
    @property
    def count(self):
        total = 0
        for val in self._cards_on_hand:
            total += val.face
        return total


def get_key(card):
    return card.face


def main():
    p = Poker()
    p.shuffle()
    user = Player('ljl')
    com1 = Player('c1')
    while p.has_next:
        print()
        print('玩家:%d-------電腦:%d' % (user.count, com1.count))
        if user.count > 0:
            for i in user.cards_on_hand:
                print(i, end='')
            print('-------------', end='')
            for i in com1.cards_on_hand:
                print(i, end='')
        f = input('是否還要繼續(xù)游戲y or n:')
        if f == 'y':
            user.get(p.next)
            if user.count > 21:
                print('%d玩家輸了' % user.count)
                return False
        if com1.count < 15:
            com1.get(p.next)
        if com1.count > 21:
            print('玩家勝利')
            return False


if __name__ == '__main__':
    main()


?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 類動態(tài)綁定方法與限定實例屬性 類動態(tài)綁定方法 前面我們說了如何給類動態(tài)的添加屬性,那么如何動態(tài)綁定方法呢?如下示例...
    DramaScript閱讀 550評論 0 0
  • 寫在之前 因為簡書字數(shù)限制,完整版地址:https://www.zybuluo.com/hainingwyx/no...
    hainingwyx閱讀 13,985評論 0 41
  • java繼承 繼承的概念 繼承是java面向對象編程技術的一塊基石,因為它允許創(chuàng)建分等級層次的類。 繼承就是子類繼...
    863cda997e42閱讀 686評論 0 1
  • 面向對象筆記 一、 對象在內存中的存放方法以及被調用過程 class文件首先被加載到方法區(qū)中的class文件內容區(qū)...
    VictorBXv閱讀 484評論 0 2
  • 無形之中 被束縛 下午趴在桌上 聽見同事發(fā)語音 說 喜歡就不怕難堅持 是啊 若沒有喜歡 請問堅持什么呢 媽媽說 你...
    林小膽閱讀 391評論 0 0