Python第三周

面向對象的進階

包裝器:@property(getter)、@setter

之前我們討論過Python中屬性和方法訪問權限的問題,雖然我們不建議將屬性設置為私有的,但是如果直接將屬性暴露給外界也是有問題的,比如我們沒有辦法檢查賦給屬性的值是否有效。我們之前的建議是將屬性命名以單下劃線開頭,通過這種方式來暗示屬性是受保護的,不建議外界直接訪問,那么如果想訪問屬性可以通過屬性的getter(訪問器)和setter(修改器)方法進行對應的操作。如果要做到這點,就可以考慮使用@property包裝器來包裝getter和setter方法,使得對屬性的訪問既安全又方便

__ slots __方法

如果需要限定自定義類型的對象只能綁定某些屬性,可以通過在類中定義slots變量來進行限定。需要注意的是slots的限定只對當前類的對象生效,對子類并不起任何作用

class Person(object):

    # 限定Person對象只能綁定_name, _age和_gender屬性
    __slots__ = ('_name', '_age', '_gender')

    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):
        if self._age <= 16:
            print('%s正在玩飛行棋.' % self._name)
        else:
            print('%s正在玩斗地主.' % self._name)


def main():
    person = Person('王大錘', 22)
    person.play()
    person._gender = '男'
    # AttributeError: 'Person' object has no attribute '_is_gay'
    # person._is_gay = True

靜態方法和類方法

靜態方法:@staticmethod

類方法:@classmethod

類方法的第一個參數約定名為cls,它代表的是當前類相關的信息的對象(類本身也是一個對象,有的地方也稱之為類的元數據對象),通過這個參數我們可以獲取和類相關的信息并且可以創建出類的對象

from math import sqrt


class Triangle(object):

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

    @staticmethod
    def is_valid(a, b, c):
        return a + b > c and b + c > a and a + c > b

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

    def area(self):
        half = self.perimeter() / 2
        return sqrt(half * (half - self._a) *
                    (half - self._b) * (half - self._c))


def main():
    a, b, c = 3, 4, 5
    # 靜態方法和類方法都是通過給類發消息來調用的
    if Triangle.is_valid(a, b, c):
        t = Triangle(a, b, c)
        print(t.perimeter())
        # 也可以通過給類發消息來調用對象方法但是要傳入接收消息的對象作為參數
        # print(Triangle.perimeter(t))
        print(t.area())
        # print(Triangle.area(t))
    else:
        print('無法構成三角形.')


if __name__ == '__main__':
    main()
from time import time, localtime, sleep


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

    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():
    # 通過類方法創建對象并獲取系統時間
    clock = Clock.now()
    while True:
        print(clock.show())
        sleep(1)
        clock.run()


if __name__ == '__main__':
    main()

類之間的關系

1:is-a關系也叫繼承或泛化,比如學生和人的關系
2:has-a關系通常稱之為關聯,比如汽車和引擎的關系都屬于關聯關系;關聯關系如果是整體和部分的關聯,那么我們稱之為聚合關系;如果整體進一步負責了部分的生命周期(整體和部分是不可分割的,同時同在也同時消亡),那么這種就是最強的關聯關系,我們稱之為合成關系。
3:use-a關系通常稱之為依賴,比如司機有一個駕駛的行為,其中使用到了汽車,那么司機和汽車的關系就是依賴關系

繼承和多態

在已有類的基礎上創建新類,這其中的一種做法就是讓一個類從另一個類那里將屬性和方法直接繼承下來,從而減少重復代碼的編寫。提供繼承信息的我們稱之為父類,也叫超類或基類;得到繼承信息的我們稱之為子類,也叫派生類或衍生類。子類除了繼承父類提供的屬性和方法,還可以定義自己特有的屬性和方法,所以子類比父類擁有的更多的能力,在實際開發中,我們經常會用子類對象去替換掉一個父類對象,這是面向對象編程中一個常見的行為,對應的原則稱之為里式替換原則,
子類在繼承了父類的方法后,可以對父類已有的方法給出新的實現版本,這個動作稱之為方法重寫(override)。通過方法重寫我們可以讓父類的同一個行為在子類中擁有不同的實現版本,當我們調用這個經過子類重寫的方法時,不同的子類對象會表現出不同的行為,這個就是多態

補充

函數的參數
必選參數
默認值
可變參數(args)
關鍵字參數(
*kwargs)
命名關鍵字參數

  def f1(a,b,c=0,*args,**kw):  
    print(a,b,c,args,kw)  
  
#調用情況:  
f1(1,2)  
f1(1,2,c=4)  
f1(1,3,6,'aw','wad',x=123,y='1232')  
其中:
a,b 為必選參數
c=0 為默認參數

*args 為可變參數,可變參數允許你傳入 0個或任意個參數,這些可變參數在函數調用時自動組裝為一個tuple

**kw 為關鍵字參數,關鍵字參數允許你傳入 0個或任意個含參數名的參數,這些關鍵字參數在函數內部自動組裝為一個dict
def person(name,age,*,city='hongkong',job='coder'):  
    print(name,age,city,job)  
person('scofff',212,city='homy',job='eatter') 

后面的兩個參數為命名關鍵字參數
對于關鍵字參數,函數的調用者可以傳入任意不受限制的關鍵字參數,至于到底傳入了哪些,就需要在函數內部通過 kw 檢查。 
與關鍵字參數**kw不同,命名關鍵字參數需要一個特殊分隔符*,*后面的參數被視為命名關鍵字參數,如果沒有*號,那么后面的參數將被視為普通的未位置參數。
命名關鍵字參數必須傳入參數名,而命名關鍵字參數可以有缺省值,這和位置參數不同。

面向對象的原則

單一職責原則

單一職責原則的定義是就一個類而言,應該僅有一個引起他變化的原因。也就是說一個類應該只負責一件事情。如果一個類負責了方法M1,方法M2兩個不同的事情,當M1方法發生變化的時候,我們需要修改這個類的M1方法,但是這個時候就有可能導致M2方法不能工作。這個不是我們期待的,但是由于這種設計卻很有可能發生。所以這個時候,我們需要把M1方法,M2方法單獨分離成兩個類。讓每個類只專心處理自己的方法。
單一職責原則的好處如下:
1):可以降低類的復雜度,一個類只負責一項職責,這樣邏輯也簡單很多
2):提高類的可讀性,和系統的維護性,因為不會有其他奇怪的方法來干擾我們理解這個類的含義
3):當發生變化的時候,能將變化的影響降到最小,因為只會在這個類中做出修改

開閉原則

開閉原則的定義是軟件中的對象(類,模塊,函數等)應該對于擴展是開放的,但是對于修改是關閉的。
當需求發生改變的時候,我們需要對代碼進行修改,這個時候我們應該盡量去擴展原來的代碼,而不是去修改原來的代碼,因為這樣可能會引起更多的問題。
這個準則和單一職責原則一樣,是一個大家都這樣去認為但是又沒規定具體該如何去做的一種原則。
開閉原則我們可以用一種方式來確保他,我們用抽象去構建框架,用實現擴展細節。這樣當發生修改的時候,我們就直接用抽象了派生一個具體類去實現修改

里氏替換原則

子類可以去擴展父類的功能,但是不能改變父類原有的功能
1.子類可以實現父類的抽象方法,但是不能覆蓋父類的非抽象方法。
2.子類可以增加自己獨有的方法。
3.當子類的方法重載父類的方法時候,方法的形參要比父類的方法的輸入參數更加寬松。
4.當子類的方法實現父類的抽象方法時,方法的返回值要比父類更嚴格。

合成聚合復用原則

合成/聚合復用原則經常又叫做合成復用原則。該原則就是在一個新的對象里面使用一些已有的對象,使之成為新對象的一部分:新的對象通過向這些對象的委派達到復用已有功能的目的

迪米特法則

迪米特原則也被稱為最小知識原則
定義為一個對象應該對其他對象保持最小的了解。
因為類與類之間的關系越密切,耦合度越大,當一個類發生改變時,對另一個類的影響也越大,所以這也是我們提倡的軟件編程的總的原則:低耦合,高內聚。
使用總結:
(1).在類的劃分上,應當盡量創建松耦合的類,類之間的耦合度越低,就越有利于復用,一個處在松耦合中的類一旦被修改,不會對關聯的類造成太大波及;
(2).在類的結構設計上,每一個類都應當盡量降低其成員變量和成員函數的訪問權限;
(3).在類的設計上,只要有可能,一個類型應當設計成不變類;
(4).在對其他類的引用上,一個對象對其他對象的引用應當降到最低。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,746評論 2 370

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,707評論 18 399
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,776評論 18 139
  • 一:java概述: 1,JDK:Java Development Kit,java的開發和運行環境,java的開發...
    慕容小偉閱讀 1,810評論 0 10
  • 2 沒關系,你還有我 發布1378字 花團錦簇,香氣襲人,帝國這座六星級酒店里,所有的賓客都把目光放在高臺上一對剛...
    媛姐不是吃素的閱讀 449評論 0 0
  • 最近,有朋友向我咨詢一個問題:家有四套房,自己住一套,老公有工作,孩子也大了,自己家里呆,租金二十萬,該不該去工作...
    邊緣上的沉思閱讀 3,410評論 10 14