#!/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