標籤:http title 作用 方法 利用 處理 res __init__ 快速
多重繼承
class Student(man,oldman):
pass
可以繼承多個父類,擁有他們的方法,如果有父類有相同的方法,哪個在前用哪個
定製類
看到類似__slots__這種形如 __xxx__的變數或函數名就要注意,這些在python中是有特殊用途的
我們已經知道了__slots__的用法,用__len__()方法我們也知道是為了能讓class作用於len()函數
__str__
我們先定義一個Student類,列印一個執行個體
class Studentc(): def __init__(self,name): self.__name = nameprint(Studentc(‘cc‘))
--> <__main__.Studentc object at 0x0000000000B48B00>
列印出來一坨不好看,我們定義一下__str__()方法,返回一個好看的字串
class Studentc(): def __init__(self,name): self.__name = name def __str__(self): return ‘Studentc object (name : %s)‘% self.__nameprint(Studentc(‘cc‘)) # Studentc object (name : cc)
這裡return 不用敲print
但是直接敲變數在shell下運行,列印出來的還是不好看
123 |
>>> s = Student( ‘Michael‘ ) >>> s <__main__.Student object at 0x109afb310 > |
這是因為直接顯示變數調用的不是__str__(),而是__repr__(),兩者的區別就是__str__()返回使用者看到的字串,而__repr__返回程式開發人員看到的字串,也就是說__repr__()是為調試服務的
解決辦法是再定義一個__repr__()。但是通常兩個代碼是一樣的,可以偷懶
class Studentc(): def __init__(self,name): self.__name = name def __str__(self): return ‘Studentc object (name : %s)‘% self.__name __repr__ = __str__
__iter__
如果一個類想要被用於for in 迴圈,必須實現一個__iter__()方法,改方法返回一個迭代對象,然後就會不斷調用該迭代對象的__next__()方法拿到迴圈的下一個值,直到遇到StopIteration錯誤時退出迴圈
class Fib(): def __init__(self): self.__a,self.__b = 0,1 def __iter__(self): return self def __next__(self): self.__a,self.__b = self.__b,self.__a + self.__b if self.__a >1000: raise StopIteration else: return self.__afor x in Fib(): print(x)
__getitem__
Fib執行個體雖然能作用於for迴圈,看起來和list有點像,但是,把它當成list使用還是不行比如取第五個元素
class Suv(): def __getitem__(self,n): a,b = 0,1 for x in range(n): a,b = b,a+b return aprint(Fib()[3])
list還有切片功能,這裡不能用,因為我們不知道傳進來的是什麼需要做一個判斷
isinstance(n,slice) slice是切片的類型。還有負數等沒有處理真想完全實現的話需要添加很多
__getattr__
正常情況下,當我們調用類的方法或屬性時,如果不存在,就會報錯
避免這種情況,除了可以加上一個score屬性外,python還有另一個機智,那就是寫一個__getattr__()方法,動態返回一個屬性
class Su(): def __init__(self): self.name = ‘cc‘ def __getattr__(self, item): if item == ‘score‘: return ‘99‘print(Su().score)
當調用的屬性不存在時,比如score,python會試圖調用__getattr__(self,‘score‘)來嘗試獲得屬性,這樣我們就有機會返回score的值
返回函數也是可以的
class Student(): def __init__(self): self.name = ‘cc‘ def __getattr__(self, item): if item == ‘age‘: return lambda :25print(Student().age())
返回一個函數,調用的時候修改成Student().age()
注意,只有在沒有找到屬性的情況下,才調用__getattr__,已有的屬性,比如name,不會在__getattr__中尋找
此外,如果沒對未知的屬性做處理,if判斷輸出的話。會返回None,要讓class只響應特定的幾個屬性,我們就按照約定拋出AttributeError的錯誤
class Student(): def __init__(self): self.name = ‘cc‘ def __getattr__(self, item): if item == ‘age‘: return lambda :25 raise AttributeError(‘no have %s‘%item)print(Student().ac())
這實際上可以吧一個類的所有屬性和方法調用全部動態化處理了,不需要任何特殊手段
這種完全動態調用的特性與什麼實際作用呢?作用就是可以針對完全動態情況作調用
舉個例子
現在很多網站都搞rest api,比如新浪微博,豆瓣 調用api的url類似
http://api.server/user/friends
如果要寫sdk,給誒給url對應的api寫一個方法,那得累死,而且一旦api改動,sdk也要改
利用完全動態__getaattr__我們可以寫一個鏈式調用
class Chain(): def __init__(self,ab=""): self._path =ab def __getattr__(self, path): print(‘self._path = %s ,path = %s‘%(self._path,path)) return Chain(‘%s/%s‘ % (self._path,path)) def __str__(self): return self._path __reper__ = __str__c = Chain().status.user.time.listprint(c)
12345 |
self ._path = ,path = status self ._path = / status ,path = user self ._path = / status / user ,path = time self ._path = / status / user / time ,path = list / status / user / time / list |
屬性都不存在,每一次都調用__getattr__方法,返回當前self._path + 屬性名稱,並被_path獲得,不斷累加直到沒有屬性
列印返回self._path 的值
__call__
一個對象執行個體可以與自己的屬性和方法,當我們調用執行個體方法時,我們會用instance.methond()來調用。能不能直接在執行個體本身上調用呢,在python答案是肯定的
任何類,只需要定義一個__call__()方法,就可以直接對執行個體進行調用
class Students(): def __init__(self,name): self.name = name def __call__(self): print(‘myname is %s‘% self.name)s1 = Students(‘s1‘)s1()
__call__()還可以定義參數。對執行個體進行直接調用就好比對一個函數調用一樣,所以你完全可以把對象看出函數,把函數看成對象,因為兩者之間本來就沒有什麼根本的區別
如果你把對象看成函數,那麼函數本身其實也可以在運行期間動態建立出來的,這麼一來,我們就模糊了對象和函數的界限。
那麼如何判斷一個變數是對象還是函數呢?其實我們只需要判斷一個對象是否能被調用,能被調用的對象就是一個Callable對象,比如函數和我們上面定義的__call__()的類執行個體
print(callable(Student))print(callable([1,2,34]))print(callable(None))print(callable(‘str‘))
快速瞭解Python的定製類