__str__
__repr__
__iter__
__next__
__getitem__
__getattr__
正常情況下,當我們呼叫類的方法或屬性時,如果不存在,就會報錯。比如定義student類:
classstudent(object):def __init__(self):
self.name= 'michael'
呼叫name屬性,沒問題,但是,呼叫不存在的score屬性,就有問題了:
>>> s =student()>>> print(s.name)
michael>>> print(s.score)
traceback (most recent call last):
attributeerror:'student' object has no attribute 'score'
錯誤資訊很清楚地告訴我們,沒有找到score這個attribute。
classstudent(object):def __init__(self):
self.name= 'michael'
def __getattr__(self, attr):if attr=='score':return 99
當呼叫不存在的屬性時,比如score,python直譯器會試圖呼叫__getattr__(self, 'score')來嘗試獲得屬性,這樣,我們就有機會返回score的值:
>>> s =student()>>>s.name'michael'
>>>s.score99
返回函式也是完全可以的:
classstudent(object):def __getattr__(self, attr):if attr=='age':return lambda: 25
只是呼叫方式要變為:
>>>s.age()25
注意,只有在沒有找到屬性的情況下,才呼叫__getattr__,已有的屬性,比如name,不會在__getattr__中查詢。
此外,注意到任意呼叫如s.abc都會返回none,這是因為我們定義的__getattr__預設返回就是none。要讓class只響應特定的幾個屬性,我們就要按照約定,丟擲attributeerror的錯誤:
classstudent(object):def __getattr__(self, attr):if attr=='age':return lambda: 25
raise attributeerror('\'student\' object has no attribute \'%s\'' % attr)
這實際上可以把乙個類的所有屬性和方法呼叫全部動態化處理了,不需要任何特殊手段。
這種完全動態呼叫的特性有什麼實際作用呢?作用就是,可以針對完全動態的情況作呼叫。
舉個例子:
如果要寫sdk,給每個url對應的api都寫乙個方法,那得累死,而且,api一旦改動,sdk也要改。
利用完全動態的__getattr__,我們可以寫出乙個鏈式呼叫:
lass chain(object):def __init__(self, path=''):
self._path=pathdef __getattr__(self, path):return chain('%s/%s' %(self._path, path))def __str__(self):returnself._path__repr__ = __str__
試試:>>>chain().status.user.timeline.list'/status/user/timeline/list'
這樣,無論api怎麼變,sdk都可以根據url實現完全動態的呼叫,而且,不隨api的增加而改變!
還有些rest api會把引數放到url中,比如github的api:
get /users/:user/repos
呼叫時,需要把:user替換為實際使用者名稱。如果我們能寫出這樣的鏈式呼叫:
chain().users('michael').repos
就可以非常方便地呼叫api了。有興趣的童鞋可以試試寫出來。
__call__
乙個物件例項可以有自己的屬性和方法,當我們呼叫例項方法時,我們用instance.method()來呼叫。能不能直接在例項本身上呼叫呢?在python中,答案是肯定的。
任何類,只需要定義乙個__call__()方法,就可以直接對例項進行呼叫。請看示例:
classstudent(object):def __init__(self, name):
self.name=namedef __call__(self):print('my name is %s.' % self.name)
呼叫方式如下:
>>> s = student('michael')>>> s() #self引數不要傳入
my name is michael.
__call__()還可以定義引數。對例項進行直接呼叫就好比對乙個函式進行呼叫一樣,所以你完全可以把物件看成函式,把函式看成物件,因為這兩者之間本來就沒啥根本的區別。
如果你把物件看成函式,那麼函式本身其實也可以在執行期動態建立出來,因為類的例項都是執行期建立出來的,這麼一來,我們就模糊了物件和函式的界限。
那麼,怎麼判斷乙個變數是物件還是函式呢?其實,更多的時候,我們需要判斷乙個物件是否能被呼叫,能被呼叫的物件就是乙個callable物件,比如函式和我們上面定義的帶有__call__()的類例項:
>>>callable(student())
true>>>callable(max)
true>>> callable([1, 2, 3])
false>>>callable(none)
false>>> callable('str')
false
通過callable()函式,我們就可以判斷乙個物件是否是「可呼叫」物件。
python定製訂單 觸發定製的Python業務
您可能知道,我們可以採用python指令碼語言來提供業務。這種方式可以非常靈活地滿足許多客戶各種各樣的需求。但是某些東西就不那麼靈活,例如業務的觸發方式。以前的mss版本在卡號業務中,固定了業務觸發方式。也就是說,只有被叫號碼是 300 的呼叫才會觸發卡號業務。有些客戶就是不喜歡這個號碼,還有些客戶...
python定製 python中定製類
1 python中 str 和repr 如果要把乙個類的例項變成 str,就需要實現特殊方法 str classperson object def init self,name,gender self.name name self.gender genderdef str self return p...
Python 定製序列
1 python中的三大容器 列表list,元組tuple,字串string 2 python允許我們定製乙個不可變的容器,如string,中就不能有修改容器的資料方法,如 setitem delitem 3 如果希望定製的容器支援reversed 內建函式,則容器中需定義 reversed 方法,...