欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python超細(xì)致探究面向?qū)ο?/h1>
 更新時(shí)間:2022年06月28日 10:31:15   作者:五包辣條!  
面向?qū)ο缶幊淌且环N編程方式,此編程方式的落地需要使用“類”和 “對象”來實(shí)現(xiàn),所以,面向?qū)ο缶幊唐鋵?shí)就是對 “類”和“對象” 的使用,今天給大家介紹下python 面向?qū)ο箝_發(fā)及基本特征,感興趣的朋友一起看看吧

前言

面向?qū)ο缶幊虒Τ鯇W(xué)者來說不難理解但很難應(yīng)用,雖然我們?yōu)榇蠹铱偨Y(jié)過面向?qū)ο蟮娜阶叻椒ǎǘx類、創(chuàng)建對象、給對象發(fā)消息),但是說起來容易做起來難。大量的編程練習(xí)和閱讀優(yōu)質(zhì)的代碼可能是這個(gè)階段最能夠幫助到大家的兩件事情。 接下來我們還是通過經(jīng)典的案例來剖析面向?qū)ο缶幊痰闹R,同時(shí)也通過這些案例為大家講解如何運(yùn)用之前學(xué)過的Python知識。

撲克游戲。

說明:簡單起見,我們的撲克只有52張牌(沒有大小王),游戲需要將52張牌發(fā)到4個(gè)玩家的手上,每個(gè)玩家手上有13張牌,按照黑桃、紅心、草花、方塊的順序和點(diǎn)數(shù)從小到大排列,暫時(shí)不實(shí)現(xiàn)其他的功能。

使用面向?qū)ο缶幊谭椒?,首先需要從問題的需求中找到對象并抽象出對應(yīng)的類,此外還要找到對象的屬性和行為。當(dāng)然,這件事情并不是特別困難,我們可以從需求的描述中找出名詞和動詞,名詞通常就是對象或者是對象的屬性,而動詞通常是對象的行為。撲克游戲中至少應(yīng)該有三類對象,分別是牌、撲克和玩家,牌、撲克、玩家三個(gè)類也并不是孤立的。類和類之間的關(guān)系可以粗略的分為is-a關(guān)系(繼承)、has-a關(guān)系(關(guān)聯(lián))和use-a關(guān)系(依賴)。很顯然撲克和牌是has-a關(guān)系,因?yàn)橐桓睋淇擞校╤as-a)52張牌;玩家和牌之間不僅有關(guān)聯(lián)關(guān)系還有依賴關(guān)系,因?yàn)橥婕沂稚嫌校╤as-a)牌而且玩家使用了(use-a)牌。

牌的屬性顯而易見,有花色和點(diǎn)數(shù)。我們可以用0到3的四個(gè)數(shù)字來代表四種不同的花色,但是這樣的代碼可讀性會非常糟糕,因?yàn)槲覀儾⒉恢篮谔?、紅心、草花、方塊跟0到3的數(shù)字的對應(yīng)關(guān)系。如果一個(gè)變量的取值只有有限多個(gè)選項(xiàng),我們可以使用枚舉。與C、Java等語言不同的是,Python中沒有聲明枚舉類型的關(guān)鍵字,但是可以通過繼承enum模塊的Enum類來創(chuàng)建枚舉類型,代碼如下所示。

from enum import Enum
class Suite(Enum):
    """花色(枚舉)"""
    SPADE, HEART, CLUB, DIAMOND = range(4)

通過上面的代碼可以看出,定義枚舉類型其實(shí)就是定義符號常量,如SPADE、HEART等。每個(gè)符號常量都有與之對應(yīng)的值,這樣表示黑桃就可以不用數(shù)字0,而是用Suite.SPADE;同理,表示方塊可以不用數(shù)字3, 而是用Suite.DIAMOND。注意,使用符號常量肯定是優(yōu)于使用字面常量的,因?yàn)槟軌蜃x懂英文就能理解符號常量的含義,代碼的可讀性會提升很多。Python中的枚舉類型是可迭代類型,簡單的說就是可以將枚舉類型放到for-in循環(huán)中,依次取出每一個(gè)符號常量及其對應(yīng)的值,如下所示。

for suite in Suite:
    print(f'{suite}: {suite.value}')

接下來我們可以定義牌類。

class Card:
    """牌"""
    def __init__(self, suite, face):
        self.suite = suite
        self.face = face
    def __repr__(self):
        suites = '????'
        faces = ['', 'A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
        # 根據(jù)牌的花色和點(diǎn)數(shù)取到對應(yīng)的字符
        return f'{suites[self.suite.value]}{faces[self.face]}'

可以通過下面的代碼來測試下Card類。

card1 = Card(Suite.SPADE, 5)
card2 = Card(Suite.HEART, 13)
print(card1, card2)    # ?5 ?K

接下來我們定義撲克類。

import random
class Poker:
    """撲克"""
    def __init__(self):
        # 通過列表的生成式語法創(chuàng)建一個(gè)裝52張牌的列表
        self.cards = [Card(suite, face) for suite in Suite
                      for face in range(1, 14)]
        # current屬性表示發(fā)牌的位置
        self.current = 0
    def shuffle(self):
        """洗牌"""
        self.current = 0
        # 通過random模塊的shuffle函數(shù)實(shí)現(xiàn)列表的隨機(jī)亂序
        random.shuffle(self.cards)
    def deal(self):
        """發(fā)牌"""
        card = self.cards[self.current]
        self.current += 1
        return card
    @property
    def has_next(self):
        """還有沒有牌可以發(fā)"""
        return self.current < len(self.cards)

可以通過下面的代碼來測試下Poker類。

poker = Poker()
poker.shuffle()
print(poker.cards)

定義玩家類。

class Player:
    """玩家"""
    def __init__(self, name):
        self.name = name
        self.cards = []
    def get_one(self, card):
        """摸牌"""
        self.cards.append(card)
    def arrange(self):
        self.cards.sort()

創(chuàng)建四個(gè)玩家并將牌發(fā)到玩家的手上。

poker = Poker()
poker.shuffle()
players = [Player('東邪'), Player('西毒'), Player('南帝'), Player('北丐')]
for _ in range(13):
    for player in players:
        player.get_one(poker.deal())
for player in players:
    player.arrange()
    print(f'{player.name}: ', end='')
    print(player.cards)

執(zhí)行上面的代碼會在player.arrange()那里出現(xiàn)異常,因?yàn)?code>Player的arrange方法使用了列表的sort對玩家手上的牌進(jìn)行排序,排序需要比較兩個(gè)Card對象的大小,而<運(yùn)算符又不能直接作用于Card類型,所以就出現(xiàn)了TypeError異常,異常消息為:'<' not supported between instances of 'Card' and 'Card'。

為了解決這個(gè)問題,我們可以對Card類的代碼稍作修改,使得兩個(gè)Card對象可以直接用<進(jìn)行大小的比較。這里用到技術(shù)叫運(yùn)算符重載,Python中要實(shí)現(xiàn)對<運(yùn)算符的重載,需要在類中添加一個(gè)名為__lt__的魔術(shù)方法。很顯然,魔術(shù)方法__lt__中的lt是英文單詞“less than”的縮寫,以此類推,魔術(shù)方法__gt__對應(yīng)>運(yùn)算符,魔術(shù)方法__le__對應(yīng)<=運(yùn)算符,__ge__對應(yīng)>=運(yùn)算符,__eq__對應(yīng)==運(yùn)算符,__ne__對應(yīng)!=運(yùn)算符。

修改后的Card類代碼如下所示。

class Card:
    """牌"""
    def __init__(self, suite, face):
        self.suite = suite
        self.face = face
    def __repr__(self):
        suites = '????'
        faces = ['', 'A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
        # 根據(jù)牌的花色和點(diǎn)數(shù)取到對應(yīng)的字符
        return f'{suites[self.suite.value]}{faces[self.face]}'
    def __lt__(self, other):
        # 花色相同比較點(diǎn)數(shù)的大小
        if self.suite == other.suite:
            return self.face < other.face
        # 花色不同比較花色對應(yīng)的值
        return self.suite.value < other.suite.value

說明: 大家可以嘗試在上面代碼的基礎(chǔ)上寫一個(gè)簡單的撲克游戲,如21點(diǎn)游戲(Black Jack),游戲的規(guī)則可以自己在網(wǎng)上找一找。

工資結(jié)算系統(tǒng)。

要求:某公司有三種類型的員工,分別是部門經(jīng)理、程序員和銷售員。需要設(shè)計(jì)一個(gè)工資結(jié)算系統(tǒng),根據(jù)提供的員工信息來計(jì)算員工的月薪。其中,部門經(jīng)理的月薪是固定15000元;程序員按工作時(shí)間(以小時(shí)為單位)支付月薪,每小時(shí)200元;銷售員的月薪由1800元底薪加上銷售額5%的提成兩部分構(gòu)成。

通過對上述需求的分析,可以看出部門經(jīng)理、程序員、銷售員都是員工,有相同的屬性和行為,那么我們可以先設(shè)計(jì)一個(gè)名為Employee的父類,再通過繼承的方式從這個(gè)父類派生出部門經(jīng)理、程序員和銷售員三個(gè)子類。很顯然,后續(xù)的代碼不會創(chuàng)建Employee 類的對象,因?yàn)槲覀冃枰氖蔷唧w的員工對象,所以這個(gè)類可以設(shè)計(jì)成專門用于繼承的抽象類。Python中沒有定義抽象類的關(guān)鍵字,但是可以通過abc模塊中名為ABCMeta 的元類來定義抽象類。關(guān)于元類的知識,后面的課程中會有專門的講解,這里不用太糾結(jié)這個(gè)概念,記住用法即可。

from abc import ABCMeta, abstractmethod
class Employee(metaclass=ABCMeta):
    """員工"""
    def __init__(self, name):
        self.name = name
    @abstractmethod
    def get_salary(self):
        """結(jié)算月薪"""
        pass

在上面的員工類中,有一個(gè)名為get_salary的方法用于結(jié)算月薪,但是由于還沒有確定是哪一類員工,所以結(jié)算月薪雖然是員工的公共行為但這里卻沒有辦法實(shí)現(xiàn)。對于暫時(shí)無法實(shí)現(xiàn)的方法,我們可以使用abstractmethod裝飾器將其聲明為抽象方法,所謂抽象方法就是只有聲明沒有實(shí)現(xiàn)的方法,聲明這個(gè)方法是為了讓子類去重寫這個(gè)方法。接下來的代碼展示了如何從員工類派生出部門經(jīng)理、程序員、銷售員這三個(gè)子類以及子類如何重寫父類的抽象方法。

class Manager(Employee):
    """部門經(jīng)理"""
    def get_salary(self):
        return 15000.0
class Programmer(Employee):
    """程序員"""
    def __init__(self, name, working_hour=0):
        super().__init__(name)
        self.working_hour = working_hour
    def get_salary(self):
        return 200 * self.working_hour
class Salesman(Employee):
    """銷售員"""
    def __init__(self, name, sales=0):
        super().__init__(name)
        self.sales = sales
    def get_salary(self):
        return 1800 + self.sales * 0.05

上面的ManagerProgrammer、Salesman三個(gè)類都繼承自Employee,三個(gè)類都分別重寫了get_salary方法。重寫就是子類對父類已有的方法重新做出實(shí)現(xiàn)。相信大家已經(jīng)注意到了,三個(gè)子類中的get_salary各不相同,所以這個(gè)方法在程序運(yùn)行時(shí)會產(chǎn)生多態(tài)行為,多態(tài)簡單的說就是調(diào)用相同的方法,不同的子類對象做不同的事情。

我們通過下面的代碼來完成這個(gè)工資結(jié)算系統(tǒng),由于程序員和銷售員需要分別錄入本月的工作時(shí)間和銷售額,所以在下面的代碼中我們使用了Python內(nèi)置的isinstance函數(shù)來判斷員工對象的類型。我們之前講過的type函數(shù)也能識別對象的類型,但是isinstance函數(shù)更加強(qiáng)大,因?yàn)樗梢耘袛喑鲆粋€(gè)對象是不是某個(gè)繼承結(jié)構(gòu)下的子類型,你可以簡答的理解為type函數(shù)是對對象類型的精準(zhǔn)匹配,而isinstance函數(shù)是對對象類型的模糊匹配。

emps = [
    Manager('劉備'), Programmer('諸葛亮'), Manager('曹操'), 
    Programmer('荀彧'), Salesman('呂布'), Programmer('張遼'),
]
for emp in emps:
    if isinstance(emp, Programmer):
        emp.working_hour = int(input(f'請輸入{emp.name}本月工作時(shí)間: '))
    elif isinstance(emp, Salesman):
        emp.sales = float(input(f'請輸入{emp.name}本月銷售額: '))
    print(f'{emp.name}本月工資為: ¥{emp.get_salary():.2f}元')

總結(jié)

面向?qū)ο蟮木幊趟枷敕浅5暮?,也符合人類的正常思維習(xí)慣,但是要想靈活運(yùn)用面向?qū)ο缶幊讨械某橄?、封裝、繼承、多態(tài)需要長時(shí)間的積累和沉淀,這件事情無法一蹴而就,屬于“路漫漫其修遠(yuǎn)兮,吾將上下而求索”的東西。

到此這篇關(guān)于Python超細(xì)致探究面向?qū)ο蟮奈恼戮徒榻B到這了,更多相關(guān)Python 面向?qū)ο髢?nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python函數(shù)參數(shù)基礎(chǔ)介紹及示例

    Python函數(shù)參數(shù)基礎(chǔ)介紹及示例

    在聲明函數(shù)的時(shí)候,一般會根據(jù)函數(shù)所要實(shí)現(xiàn)的功能來決定函數(shù)是否需要參數(shù)。在多數(shù)情況下,我們聲明的函數(shù)都會使用到參數(shù),這篇文章主要介紹了Python函數(shù)參數(shù)
    2022-08-08
  • python關(guān)于逆序輸出留空格的方法解讀

    python關(guān)于逆序輸出留空格的方法解讀

    這篇文章主要介紹了python關(guān)于逆序輸出留空格的方法,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • 基于Python實(shí)現(xiàn)計(jì)算納什均衡的示例詳解

    基于Python實(shí)現(xiàn)計(jì)算納什均衡的示例詳解

    納什均衡是一種博弈論中的概念,它描述了一種平衡狀態(tài),其中每個(gè)參與者都不能通過獨(dú)立改變其決策來提高自己的利益。本文就來用Python中的Nashpy和PuLP實(shí)現(xiàn)計(jì)算納什均衡,感興趣的可以了解一下
    2023-02-02
  • Python 圖像處理 Pillow 庫詳情

    Python 圖像處理 Pillow 庫詳情

    這篇文章主要介紹了Python 圖像處理 Pillow 庫,圖像處理是常用的技術(shù),python 擁有豐富的第三方擴(kuò)展庫,Pillow 是 Python3 最常用的圖像處理庫,目前最高版本5.2.0。Python2 使用Pil庫,兩者是使用方法差不多,區(qū)別在于類的引用不同。下面來看看文章的詳細(xì)內(nèi)容
    2021-11-11
  • 淺談pandas關(guān)于查看庫或依賴庫版本的API原理

    淺談pandas關(guān)于查看庫或依賴庫版本的API原理

    本文主要介紹了淺談pandas關(guān)于查看庫或依賴庫版本的API原理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • Python OpenCV處理圖像之濾鏡和圖像運(yùn)算

    Python OpenCV處理圖像之濾鏡和圖像運(yùn)算

    這篇文章主要為大家詳細(xì)介紹了Python OpenCV處理圖像之濾鏡和圖像運(yùn)算,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • python不相等的兩個(gè)字符串的 if 條件判斷為True詳解

    python不相等的兩個(gè)字符串的 if 條件判斷為True詳解

    這篇文章主要介紹了python不相等的兩個(gè)字符串的 if 條件判斷為True詳解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-03-03
  • Python實(shí)現(xiàn)21點(diǎn)小游戲的示例代碼

    Python實(shí)現(xiàn)21點(diǎn)小游戲的示例代碼

    1931年,當(dāng)美國內(nèi)華達(dá)州宣布賭博為合法活動時(shí),21點(diǎn)游戲第一次公開出現(xiàn)在內(nèi)華達(dá)州的賭場俱樂部,15年內(nèi),它取代擲骰子游戲,而一舉成為非常流行的賭場莊家參與的賭博游戲。本文將用Python實(shí)現(xiàn)這一經(jīng)典游戲,感興趣的可以了解一下
    2022-09-09
  • PYTHON EVAL的用法及注意事項(xiàng)解析

    PYTHON EVAL的用法及注意事項(xiàng)解析

    這篇文章主要介紹了PYTHON EVAL的用法及注意事項(xiàng)解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • 解決Python 中JSONDecodeError: Expecting value: line 1 column 1 (char 0)錯(cuò)誤

    解決Python 中JSONDecodeError: Expecting value:&n

    這篇文章主要介紹了解決Python 中JSONDecodeError: Expecting value: line 1 column 1 (char 0)錯(cuò)誤問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-03-03

最新評論