詳解python中的__new__方法
阿新 • • 發佈:2019-02-11
python中的__new__方法的使用
一丶object類中對__new__方法的定義
class object:
@staticmethod # known case of __new__
def __new__(cls, *more): # known special case of object.__new__
""" T.__new__(S, ...) -> a new object with type S, a subtype of T """
pass
object將__new__()方法定義為靜態方法,並且至少需要傳遞一個引數cls,cls表示需要例項化的類,此引數在例項化時由Python直譯器自動提供。
繼承自object的新式類才有__new__
在任何新式類的__new__()方法,不能呼叫自身的__new__()來製造例項,因為這會造成死迴圈,如果當前類中沒有重寫__new__方法,那麼就追溯到父類,一直到object基類
使用object或者沒有血緣關係的新式類的__new__()是安全的,但是如果是在有繼承關係的兩個類之間,應避免互調造成死迴圈 (子類呼叫父類,父類呼叫子類)
二丶我們來看下面類中對__new__()方法的實現:
class Demo(object):
def __init__(self):
print '__init__() called...'
def __new__(cls, *args, **kwargs):
print '__new__() - {cls}'.format(cls=cls)
return object.__new__(cls, *args, **kwargs)
if __name__ == '__main__':
de = Demo()
輸出:
__new__() - <class '__main__.Demo'>
__init__() called...
發現例項化物件的時候,呼叫__init__()初始化之前,先呼叫了__new__()方法
__new__()必須要有返回值,返回例項化出來的例項,需要注意的是,可以return父類__new__()出來的例項,也可以直接將object的__new__()出來的例項返回。
__init__()有一個引數self,該self引數就是__new__()返回的例項,__init__()在__new__()的基礎上可以完成一些其它初始化的動作,__init__()不需要返回值。
若__new__()沒有正確返回當前類cls的例項,那__init__()將不會被呼叫,即使是父類的例項也不行。
我們可以將類比作製造商,__new__()方法就是前期的原材料購買環節,__init__()方法就是在有原材料的基礎上,加工,初始化商品環節。
三丶實際應用過程中,我們可以這麼使用:
class LxmlDocument(object_ref):
cache = weakref.WeakKeyDictionary()
__slots__ = ['__weakref__']
def __new__(cls, response, parser=etree.HTMLParser):
cache = cls.cache.setdefault(response, {})
if parser not in cache:
obj = object_ref.__new__(cls)
cache[parser] = _factory(response, parser)
return cache[parser]
該類中的__new__()方法的使用,就是再進行初始化之前,檢查快取中是否存在該物件,如果存在則將快取存放物件直接返回,
如果不存在,則將物件放至快取中,供下次使用。
補充丶 __call__
物件通過提供__call__(slef, [,*args [,**kwargs]])方法可以模擬函式的行為,如果一個物件x提供了該方法,就可以像函式一樣使用它,也就是說x(arg1, arg2...)
等同於呼叫x.__call__(self, arg1, arg2) 。模擬函式的物件可以用於建立防函式(functor) 或代理(proxy).
class Foo(object):
def __call__(self):
pass
f = Foo()#類Foo可call
f()#物件f可call
__init__
__init__ 方法通常用在初始化一個類例項的時候。在呼叫該初始化方法之前,需要呼叫一下__new__方法來例項化一個物件並返回,返回的內容即初始化方法中的第一個引數self
一丶object類中對__new__方法的定義
class object:
@staticmethod # known case of __new__
def __new__(cls, *more): # known special case of object.__new__
""" T.__new__(S, ...) -> a new object with type S, a subtype of T """
pass
object將__new__()方法定義為靜態方法,並且至少需要傳遞一個引數cls,cls表示需要例項化的類,此引數在例項化時由Python直譯器自動提供。
繼承自object的新式類才有__new__
在任何新式類的__new__()方法,不能呼叫自身的__new__()來製造例項,因為這會造成死迴圈,如果當前類中沒有重寫__new__方法,那麼就追溯到父類,一直到object基類
使用object或者沒有血緣關係的新式類的__new__()是安全的,但是如果是在有繼承關係的兩個類之間,應避免互調造成死迴圈 (子類呼叫父類,父類呼叫子類)
二丶我們來看下面類中對__new__()方法的實現:
class Demo(object):
def __init__(self):
print '__init__() called...'
def __new__(cls, *args, **kwargs):
print '__new__() - {cls}'.format(cls=cls)
return object.__new__(cls, *args, **kwargs)
if __name__ == '__main__':
de = Demo()
輸出:
__new__() - <class '__main__.Demo'>
__init__() called...
發現例項化物件的時候,呼叫__init__()初始化之前,先呼叫了__new__()方法
__new__()必須要有返回值,返回例項化出來的例項,需要注意的是,可以return父類__new__()出來的例項,也可以直接將object的__new__()出來的例項返回。
__init__()有一個引數self,該self引數就是__new__()返回的例項,__init__()在__new__()的基礎上可以完成一些其它初始化的動作,__init__()不需要返回值。
若__new__()沒有正確返回當前類cls的例項,那__init__()將不會被呼叫,即使是父類的例項也不行。
我們可以將類比作製造商,__new__()方法就是前期的原材料購買環節,__init__()方法就是在有原材料的基礎上,加工,初始化商品環節。
三丶實際應用過程中,我們可以這麼使用:
class LxmlDocument(object_ref):
cache = weakref.WeakKeyDictionary()
__slots__ = ['__weakref__']
def __new__(cls, response, parser=etree.HTMLParser):
cache = cls.cache.setdefault(response, {})
if parser not in cache:
obj = object_ref.__new__(cls)
cache[parser] = _factory(response, parser)
return cache[parser]
該類中的__new__()方法的使用,就是再進行初始化之前,檢查快取中是否存在該物件,如果存在則將快取存放物件直接返回,
如果不存在,則將物件放至快取中,供下次使用。
補充丶 __call__
物件通過提供__call__(slef, [,*args [,**kwargs]])方法可以模擬函式的行為,如果一個物件x提供了該方法,就可以像函式一樣使用它,也就是說x(arg1, arg2...)
等同於呼叫x.__call__(self, arg1, arg2) 。模擬函式的物件可以用於建立防函式(functor) 或代理(proxy).
class Foo(object):
def __call__(self):
pass
f = Foo()#類Foo可call
f()#物件f可call
__init__
__init__ 方法通常用在初始化一個類例項的時候。在呼叫該初始化方法之前,需要呼叫一下__new__方法來例項化一個物件並返回,返回的內容即初始化方法中的第一個引數self