面向對象高級編程
1、對實例進行添加或修改屬性都不會影響到calss,那麼其他的實例也將或不共享新加的屬性,這時候我們可以通過給class綁定屬性達到所有實例均可調用的效果;(這是像java靜態語言很難實現的)
2、__slots__
:限制該class實例能添加的屬性,只對當前的類起作用,對子類並沒有用,除非在子類中也定義一個__slots__
;
class Student(object):
__slots__ = ('name', 'age') # 用tuple定義允許綁定的屬性名稱
3、@property
:把一個方法變成屬性調用當一個屬性調用時實際上轉化成了get_name();
@name.setter
:調用屬性時實際轉化成了set_name();
訪問時直接實例名.屬性名即可;賦值時調用的就是set方法沒有的時候調用的get方法
多重繼承(java裏面是沒有多重繼繼承的接口能達到僞多重繼承的效果)
class Mammal(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
Mixln(多重繼承設計)
定製類
1、__str__
類似於java的toString()
功能,但若使用print則調用的不是__str__()
方法而是__repr__()
調試服務的
2、__iter__()
返回一個迭代對象;
3、__getitem__()
實現此方法後可以按下標取值;
如果要使用切片功能則只需要加一個判斷代碼如下:
class Fib(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
L = []
for x in range(stop):
if x >= start:
L.append(a)
a, b = b, a + b
return L
4、__getattr__
在沒有找到屬性的情況下,調用__getattr__
;
5、__call__()
方法,就可以直接對實例進行調用;
枚舉類
兩種定義方式:
1、屬性自動賦值,默認從1開始
for name, member in Month.__members__.items():
print(name, '=>', member, ',', member.value)
2、自定義賦值Enum派生類:@unique
裝飾器檢查是否有重複值
from enum import Enum, unique
@unique
class Weekday(Enum):
Sun = 0 # Sun的value被設定爲0
Mon = 1
Tue = 2
Wed = 3
Thu = 4
Fri = 5
Sat = 6
元類
1、python是屬於動態語言,而動態語言和靜態語言最大的區別就是函數和累得定義不是編譯時定義的,而是運行時動態創建的;
2、type()
函數既可以返回一個函數類型又可以創建出新的類型;
Hello = type('Hello', (object,), dict(hello=fn)) # 創建Hello class
三個參數:
a.Class的名稱;
b.繼承的父類集合,Python支持多繼承,若只有一個父類別忘了tuple的單個元素寫法;
c.Class的方法名稱與函數綁定,這裏我們吧函數fn綁定到方法名hello上;
3、metaclass控制類的創建行爲:(很魔幻,用的少,很難)
a)先定義Metaclass,再創建類,最後創建實例;
b)四個參數: 當前準備創建的類的對象; 類的名字; 類繼承的父類集合; 類的方法集合。
# metaclass是類的模板,所以必須從`type`類型派生:class ListMetaclass(type):
def __new__(cls, name, bases, attrs):
attrs['add'] = lambda self, value: self.append(value)
return type.__new__(cls, name, bases, attrs)