"""
py魔法方法.py
(__new__/metaclass元類、__init__、__getattr__、__callable__等)
使用:
1、#使用__new__() 來定義創建對象的方式。
2、#使用__init__() 來初始化創建的實例對象。
3、#使用:__str__()魔法方法來定義print輸出
4、#使用:__repr__()魔法方法來定義調試輸出,即非print輸出
5、#使用:__iter__及__next__魔法方法來定義 對象的迭代循環。
6、#使用:__getitem__來定義迭代對象的指定索引,即列表的索引
#注意:__getitem__通過實例對象的輸入參數類型是否slice,來實現切片操作。
7、#使用:__getattr__魔法方法 動態返回一個屬性
#注意:__getattr__只有在沒找到屬性的情況下才調用,已有的屬性不會在__getattr__中查找。
8、#使用:__call__魔法方法 來使 類的實例對象可以直接實例對象()調用。即:實例對象() 的格式進行輸出
#對實例對象進行直接調用就好比對一個函數進行調用一樣,可以定義參數等。
#注意:實例對象調用 和 函數調用的概念區別,實質一樣。
#使用:callable()函數來判斷一個對象是否是 可調用對象,即:是否能被調用()。
"""
#################### 定製類:魔法方法/特殊屬性方法
#使用:特殊屬性和特殊方法(__xxx__格式的屬性方法)可以在類定義中進行定製類操作。
#定製類官方參考網址:https://docs.python.org/zh-cn/3/reference/datamodel.html#special-method-names
#__new__、__init__(創建對象、初始化對象)
#構造方法包括創建對象和初始化對象,在python當中,分爲兩步執行:先執行__new__方法,然後執行__init__方法;
##########
#使用__new__() 來定義創建對象的方式。
#__new__ 在實例創建之前被調用的,因爲它的任務就是創建實例然後返回該實例,是個靜態方法。
#使用:metaclass控制類的創建行爲,根據metaclass創建出類,即:先定義metaclass,就可以創建類,最後創建實例。
#metaclass允許創建類或者修改類,也可以把類看成是metaclass創建出來的“實例”。
#注意:默認metaclass的類名總是以Metaclass結尾,以便清楚地表示這是一個metaclass
#注意: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) #返回type()創建類的__new__方法。
#####
#使用:__new__魔法方法定義類創建過程。
#__new__()方法接收到的參數依次是:
#參數1:當前準備創建的類的對象;
#參數2:類的名字;
#參數3:類繼承的父類集合;
#參數4:類的方法集合。
##########
#使用__init__() 來初始化創建的實例對象。
#__init__ 當實例對象創建完成後被調用的,然後設置對象屬性的一些初始值。
#####
#使用:super函數 調用父類方法。
#使用:super(子類名,self).__init__() 來顯示調用 父類初始化方法
#注意:Python3可以使用直接使用 super().xxx 代替 super(Class, self).xxx :
#子類沒有定義自己的初始化函數,父類的初始化函數會被默認調用:
#定義父類:Parent
class Parent(object):
def __init__(self, name):
self.name = name
print("create an instance of:", self.__class__.__name__)
print("name attribute is:", self.name)
#定義子類Child ,繼承父類Parent
class Child(Parent):
pass
#子類實例化時,由於子類沒有初始化,此時父類的初始化函數就會默認被調用
#且必須傳入父類的參數name
c = Child("init Child")
#子類定義了自己的初始化函數,而在子類中沒有顯示調用父類的初始化函數,則父類的屬性不會被初始化
class Child(Parent):
#子類中沒有顯示調用父類的初始化函數,相當於重寫了初始化方法。
def __init__(self):
print("call __init__ from Child class")
c = Child("init Child")
print()
#子類定義了自己的初始化函數,顯示調用父類,子類和父類的屬性都會被初始化
class Child(Parent):
def __init__(self):
print('Call __init__ from Child class')
super(Child,self).__init__('data from Child') #要將子類Child和self傳遞進去
d=Parent('Tom')
c=Child()
print(c.name)
##########
#__str__(定義print輸出)、__repr__(定義調試輸出)
#使用:__str__()魔法方法來定義print輸出
#使用:__repr__()魔法方法來定義調試輸出,即非print輸出
class Student(object):
def __init__(self,name):
self.name=name
def __str__(self):
""" #使用:__str__()魔法方法來定義print輸出"""
return 'print輸出內容:\nStudent Object (name:{})'.format(self.name)
"""將輸出設置一致"""
# __repr__=__str__
def __repr__(self):
"""#使用:__repr__()魔法方法來定義調試輸出,即非print輸出"""
return '調試輸出內容: \nStudent Object (name:{})'.format(self.name)
print(Student('Michael'))
Student('Michael')
##########
#__iter__、__next__(定義循環可迭代對象)
#使用:__iter__及__next__魔法方法來定義 對象的迭代循環。
#定義斐波那契數列類
class Fib(object):
def __init__(self):
self.a, self.b=0,1
def __iter__(self):
"定義迭代返回值,如果返回None則表示不可迭代"
return self #實例本身就是迭代對象,所有返回自己本身
def __next__(self):
self.a, self.b=self.b, self.a+self.b
if self.a>1000:
raise StopIteration()
return self.a
Fib()
for f in Fib():
print(f)
##########
#__getitem__(定義迭代的指定索引)
#使用:__getitem__來定義迭代對象的指定索引,即列表的索引
#注意:__getitem__通過實例對象的輸入參數類型是否slice,來實現切片操作。
#使用:__getitem__來定義迭代對象的指定索引,即列表的索引
class Fib(object):
def __getitem__(self,n):
a,b=1,1
for x in range(n):
a,b=b,a+b
return a
f=Fib()
f[5] #像list那樣按照下標取出元素
#注意:__getitem__通過實例對象的輸入參數類型是否slice,來實現切片操作。
#定義迭代對象的 切片操作 slice
class Fib(object):
def __getitem__(self,n):
"""如果輸入參數屬於 int整數類型,則輸出該索引對應的值"""
if isinstance(n,int):
a,b=1,1
for x in range(n):
a,b=b,a+b
return a
"""通過對 實例對象的參數判斷 來實現切片操作;
即:如果輸入參數屬於 slice,則定義並返回新的列表"""
if isinstance(n,slice):
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來形成返回結果用的L列表,即切片的結果。
a,b=b,a+b
return L
f=Fib()
f[1:6]
##########
#__getattr__
#使用:__getattr__魔法方法 動態返回一個屬性
#注意:__getattr__只有在沒找到屬性的情況下才調用,已有的屬性不會在__getattr__中查找。
class Student(object):
def __init__(self):
self.name='Michael'
"""
#使用:__getattr__魔法方法 動態返回一個屬性;
#注意:__getattr__只有在沒找到屬性的情況下才調用,已有的屬性不會在__getattr__中查找。
"""
def __getattr__(self,attr):
if attr == 'score':
return 99
s=Student()
s.name
s.score
class Student(object):
def __getattr__(self,attr):
if attr == 'age':
return lambda:25 #返回函數也是完全可以的。只是需要注意調用的時候加上括號()
return AttributeError('\'Stuende類對象沒有屬性{}'.format(attr))
s=Student()
s.age() #注意調用的時候加上括號,因爲__getattr__裏定義返回的是函數。
s.time
"""沒有定義__call__魔法方法的類不能直接通過類實例對象名()如函數般來調用"""
#s().time
#通過重寫類的__getattr__ 及 __str__方法實現鏈式調用Api輸出。
class Chain(object):
def __init__(self,path=''):
self._path=path
def __getattr__(self,path):
return Chain('{}/{}'.format(self._path, path))
def __str__(self):
return self._path
__repr__=__str__
Chain().status
Chain().users.ker945.git
##########
#__call__:實例對象()調用
#使用:__call__魔法方法 來使 類的實例對象可以直接實例對象()調用。即:實例對象() 的格式進行輸出
#對實例對象進行直接調用就好比對一個函數進行調用一樣,可以定義參數等。
#注意:實例對象調用 和 函數調用的概念區別,實質一樣。
#使用:callable()函數來判斷一個對象是否是 可調用對象,即:是否能被調用()。
class Student(object):
def __init__(self,name):
self.name=name
def __call__(self,age=10):
print('My name is {},My age is {}'.format(self.name,age))
s=Student('Michael')
"""定義__call__魔法方法的類,可以直接通過類實例對象名()如函數般來調用,否則不能直接類實例對象名()調用"""
s(11)
"""如果__call__類對象如函數般調用,則就模糊了對象和函數的界限;則通過callable()函數來判斷對象是否可調用"""
callable(Student('xiaowang'))
callable(max)
callable(1)
callable('str')
py魔法方法(__new__/metaclass元類、__init__、__getattr__、__callable__等)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.