python學習筆記(四)---高級OOP

依據廖雪峯官方網站的python教程整理

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

__author__ = "Kingrumn"

'''
    高級OOP
    __xx__ 特殊屬性的用法
    枚舉類
    元類
    多重繼承

'''

from enum import Enum, unique


# 正常情況下,當我們定義了一個class,創建了一個class的實例後,我們可以給該實例綁定任何屬性和方法
# 動態綁定允許我們在程序運行的過程中動態給class加上功能


# 使用__slots__,可以限制實例的屬性
# __slots__定義的屬性僅對當前類實例起作用,對繼承的子類是不起作用的:
class StudentSlot(object):
    # 只允許實例添加name和age屬性。
    __slots__ = ('name', 'age')  # 用tuple定義允許綁定的屬性名稱


lily = StudentSlot()
lily.age = 19
lily.name = "Lily"


# lily.score = 89     # AttributeError: 'StudentSlot' object has no attribute 'score'


# 利用@property裝飾器把一個方法變成屬性調用
class StudentProp(object):

    @property
    def score(self):
        return self._score

    @score.setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value


jim = StudentProp()
jim.score = 60
print(jim.score)


# jim.score = 9999    # ValueError: score must between 0 ~ 100!


# 定義只讀屬性,只定義getter方法,不定義setter方法就是一個只讀屬性
class StudentRd(object):

    @property
    def birth(self):
        return self._birth

    @birth.setter
    def birth(self, value):
        self._birth = value

    @property
    def age(self):  # birth是可讀寫屬性,而age就是一個只讀屬性,因爲age可以根據birth和當前時間計算出來
        return 2015 - self._birth


# 類的繼承可能分爲多個維度
# 動物---哺乳動物,鳥類;
# 動物---會跑的動物,會飛的動物;
# 動物---寵物,非寵物
# 通過多重繼承,一個子類就可以同時獲得多個父類的所有功能
# 這種設計通常稱之爲MixIn

class Animal(object):
    pass


# 大類:
class Mammal(Animal):
    pass


class Bird(Animal):
    pass


# 大類
class Runnable(object):
    def run(self):
        print('Running...')


class Flyable(object):
    def fly(self):
        print('Flying...')


# 具體動物類
class Dog(Mammal, Runnable):
    pass


class Bat(Mammal, Flyable):
    pass


# 類中__xx__的特殊作用
# __slots__     用於限制屬性
# __len__()     使類可用於len()方法
# __str__()     打印實例的顯示方法, __repr__ 是爲調試服務的,作用同
class StudentStr(object):
    def __init__(self, name):
        self.name = name

    def __str__(self):  # 用於print打印
        return 'Student object (name: %s)' % self.name

    __repr__ = __str__  # 用於命令行打印


print(StudentStr('Michael'))  # Student object (name: Michael)


# __iter__      提供使用for...in的能力
class FibIter(object):
    def __init__(self):
        self.a, self.b = 0, 1  # 初始化兩個計數器a,b

    def __iter__(self):
        return self  # 實例本身就是迭代對象,故返回自己

    def __next__(self):
        self.a, self.b = self.b, self.a + self.b  # 計算下一個值
        if self.a > 100000:  # 退出循環的條件
            raise StopIteration()
        return self.a  # 返回下一個值


# __getitem__       提供下標訪問的能力
class FibGetitem(object):
    def __getitem__(self, n):
        a, b = 1, 1
        for x in range(n):
            a, b = b, a + b
        return a


FibGetitem()[5]


# 使fib可以用切片
class FibSlice(object):
    def __getitem__(self, n):
        if isinstance(n, int):  # n是索引
            a, b = 1, 1
            for x in range(n):
                a, b = b, a + b
            return a
        if isinstance(n, slice):  # n是切片
            start = n.start
            stop = n.stop
            if start is None:
                start = 0
            a, b = 1, 1
            ll = []
            for x in range(stop):
                if x >= start:
                    ll.append(a)
                a, b = b, a + b
            return ll


f = FibSlice()
print(f[0:5])


# __getattr__   控制訪問屬性的行爲
class StudentGetAttr(object):

    def __init__(self):
        self.name = 'Michael'

    def __getattr__(self, attr):
        if attr == 'score':
            return 99


s = StudentGetAttr()
print(s.score)  # 99


# 利用getattr實現鏈式調用
class Chain(object):

    def __init__(self, path=''):
        self._path = path

    def __getattr__(self, path):
        return Chain('%s/%s' % (self._path, path))

    def __str__(self):
        return self._path

    __repr__ = __str__


print(Chain().status.user.timeline.list)  # '/status/user/timeline/list'


# __call__  提供了直接調用實例的能力
class StudentCall(object):
    def __init__(self, name):
        self.name = name

    def __call__(self):
        print('My name is %s.' % self.name)


s = StudentCall('Michael')
s()  # My name is Michael.

# 使用枚舉類
# from enum import Enum
Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))

# 可以枚舉所有成員,value屬性則是自動賦給成員的int常量,默認從1開始計數。
for name, member in Month.__members__.items():
    print(name, '=>', member, ',', member.value)  # Jan => Month.Jan , 1 ...

# 也可以直接訪問
print(Month.Jan)  # Month.Jan


# 從Enum派生出自定義類,更精確地控制枚舉類型
# from enum import Enum, unique
@unique  # @unique裝飾器可以幫助我們檢查保證沒有重複值
class Weekday(Enum):
    Sun = 0  # Sun的value被設定爲0
    Mon = 1
    Tue = 2
    Wed = 3
    Thu = 4
    Fri = 5
    Sat = 6


# 訪問方法
print(Weekday.Tue)
print(Weekday['Tue'])
print(Weekday(1))

# 元類---ToDo

更多更及時的博客更新請戳—> KingRumn

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章