本篇用來(lái)介紹Python面向?qū)ο蟮乃枷?,以及里邊三個(gè)核心的方法。
1. __init__()與__new__()
示例代碼
# 實(shí)際上python3里已經(jīng)可以不用顯示地寫(xiě)出繼承自O(shè)bject類了,這里寫(xiě)上python3也不會(huì)報(bào)錯(cuò)
class A(object):
def __init__(self):
print('__init__ function')
super(A, self).__init__()
def __new__(cls):
print('__new__ function')
self = super(A, cls).__new__(cls)
return self
if __name__ == '__main__':
a = A()
輸出
__new__ function
__init__ function
從輸出結(jié)果來(lái)看, __new__()先被調(diào)用,返回一個(gè)實(shí)例對(duì)象,接著__init__() 被調(diào)用。
重點(diǎn)來(lái)了:實(shí)際上這里邊的具體過(guò)程是,__new__ ()的返回值就是類的實(shí)例對(duì)象,這個(gè)實(shí)例對(duì)象會(huì)傳遞給 __init__() 中定義的 self 參數(shù),以便實(shí)例對(duì)象可以被正確地初始化。
2. __call__()方法
可調(diào)用對(duì)象包括自定義的函數(shù)、內(nèi)置函數(shù)和類??梢酝ㄟ^(guò)一個(gè)在可調(diào)用對(duì)象后邊加一個(gè)()來(lái)對(duì)其進(jìn)行調(diào)用。可以用callable()判斷是否是可調(diào)用對(duì)象?;谏线吥莻€(gè)代碼塊
a = A()
print(callable(A))
print(callable(a))
輸出
__new__ function
__init__ function
True
False
這里之所以實(shí)例對(duì)象不是可調(diào)用對(duì)象,是因?yàn)轭愔袥](méi)有實(shí)現(xiàn)__call__()方法。如果在類中實(shí)現(xiàn)了 __call__() 方法,那么實(shí)例對(duì)象也將是一個(gè)可調(diào)用對(duì)象。
同樣的代碼,加入__call__()方法
class A(object):
def __init__(self):
print('__init__ function')
super(A, self).__init__()
def __new__(cls):
print('__new__ function')
self = super(A, cls).__new__(cls)
return self
# 這里可以傳參,作為可調(diào)用對(duì)象的參數(shù)
def __call__(self, name):
print('__call__ function name is %s'%name)
if __name__ == '__main__':
a = A()
print(callable(A))
print(callable(a))
a('abc')
輸出
__new__ function
__init__ function
True
True
__call__ function name is abc
輸出說(shuō)明三個(gè)函數(shù)的調(diào)用順序是:
__new__()、__init__()、__call__()
并且,加入__call__()后實(shí)例化對(duì)象也成為了可調(diào)用對(duì)象,并且可以通過(guò)傳參來(lái)調(diào)用
接下來(lái)列舉一些關(guān)于__call__()的一些例子,代碼都是來(lái)自于stackoverflow,有了前邊的儲(chǔ)備,例子很簡(jiǎn)單,不做解釋
①
class Factorial:
def __init__(self):
self.cache = {}
def __call__(self, n):
if n not in self.cache:
if n == 0:
self.cache[n] = 1
else:
self.cache[n] = n * self.__call__(n-1)
return self.cache[n]
if __name__ == '__main__':
fact = Factorial()
for i in range(10):
print("{}! = {}".format(i, fact(i)))
輸出
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
利用裝飾器的思想,計(jì)算函數(shù)被調(diào)用了多少次
class Counter:
def __init__(self, func):
self.func = func
self.count = 0
def __call__(self, *args, **kwargs):
self.count += 1
return self.func(*args, **kwargs)
@Counter
def foo():
pass
if __name__ == '__main__':
for i in range(10):
foo()
print(foo.count)
輸出
10