1、init 方法是什麼?python
使用Python寫過面向對象的代碼的同窗,可能對 init 方法已經很是熟悉了,init 方法一般用在初始化一個類實例的時候。例如:設計模式
#-*- coding: utf-8 -*-
class Person(object):
"""Silly Person"""
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return '<Person: %s(%s)>' % (self.name, self.age)
if __name__ == '__main__':
piglei = Person('piglei', 24)
print piglei
複製代碼
這樣即是__init__最普通的用法了。但__init__其實不是實例化一個類的時候第一個被調用 的方法。 當使用 Persion(name, age) 這樣的表達式來實例化一個類時,最早被調用的方法 實際上是 new 方法。學習
1、init 方法是什麼?spa
使用Python寫過面向對象的代碼的同窗,可能對 init 方法已經很是熟悉了,init 方法一般用在初始化一個類實例的時候。例如:設計
''' 遇到問題沒人解答?小編建立了一個Python學習交流QQ羣:857662006 尋找有志同道合的小夥伴,互幫互助, 羣裏還有不錯的視頻學習教程和PDF電子書! '''
#-*- coding: utf-8 -*-
class Person(object):
"""Silly Person"""
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return '<Person: %s(%s)>' % (self.name, self.age)
if __name__ == '__main__':
piglei = Person('piglei', 24)
print piglei
複製代碼
這樣即是__init__最普通的用法了。但__init__其實不是實例化一個類的時候第一個被調用 的方法。 當使用 Persion(name, age) 這樣的表達式來實例化一個類時,最早被調用的方法 實際上是 new 方法。code
2、new 方法是什麼? __new__方法接受的參數雖然也是和__init__同樣,但__init__是在類實例建立以後調用,而 __new__方法正是建立這個類實例的方法。視頻
''' 遇到問題沒人解答?小編建立了一個Python學習交流QQ羣:857662006 尋找有志同道合的小夥伴,互幫互助, 羣裏還有不錯的視頻學習教程和PDF電子書! '''
# -*- coding: utf-8 -*-
class Person(object):
"""Silly Person"""
def __new__(cls, name, age):
print '__new__ called.'
return super(Person, cls).__new__(cls, name, age)
def __init__(self, name, age):
print '__init__ called.'
self.name = name
self.age = age
def __str__(self):
return '<Person: %s(%s)>' % (self.name, self.age)
if __name__ == '__main__':
piglei = Person('piglei', 24)
print piglei
複製代碼
執行結果:對象
piglei@macbook-pro:blog$ python new_and_init.py
__new__ called.
__init__ called.
<Person: piglei(24)>
複製代碼
經過運行這段代碼,咱們能夠看到,__new__方法的調用是發生在__init__以前的。其實當 你實例化一個類的時候,具體的執行邏輯是這樣的:blog
3、new 的做用繼承
依照Python官方文檔的說法,__new__方法主要是當你繼承一些不可變的class時(好比int, str, tuple), 提供給你一個自定義這些類的實例化過程的途徑。還有就是實現自定義的metaclass。 首先咱們來看一下第一個功能,具體咱們能夠用int來做爲一個例子:
假如咱們須要一個永遠都是正數的整數類型,經過集成int,咱們可能會寫出這樣的代碼。
''' 遇到問題沒人解答?小編建立了一個Python學習交流QQ羣:857662006 尋找有志同道合的小夥伴,互幫互助, 羣裏還有不錯的視頻學習教程和PDF電子書! '''
class PositiveInteger(int):
def __init__(self, value):
super(PositiveInteger, self).__init__(self, abs(value))
i = PositiveInteger(-3)
print i
複製代碼
但運行後會發現,結果根本不是咱們想的那樣,咱們任然獲得了-3。這是由於對於int這種 不可變的對象,咱們只有重載它的__new__方法才能起到自定義的做用。 這是修改後的代碼:
''' 遇到問題沒人解答?小編建立了一個Python學習交流QQ羣:857662006 尋找有志同道合的小夥伴,互幫互助, 羣裏還有不錯的視頻學習教程和PDF電子書! '''
class PositiveInteger(int):
def __new__(cls, value):
return super(PositiveInteger, cls).__new__(cls, abs(value))
i = PositiveInteger(-3)
print i
複製代碼
經過重載__new__方法,咱們實現了須要的功能。 另一個做用,關於自定義metaclass。其實我最先接觸__new__的時候,就是由於須要自定義 metaclass,但鑑於篇幅緣由,咱們下次再來說python中的metaclass和__new__的關係。
4、用__new__來實現單例
事實上,當咱們理解了__new__方法後,咱們還能夠利用它來作一些其餘有趣的事情,好比實現 設計模式中的 單例模式(singleton) 。 由於類每一次實例化後產生的過程都是經過__new__來控制的,因此經過重載__new__方法,咱們 能夠很簡單的實現單例模式。
''' 遇到問題沒人解答?小編建立了一個Python學習交流QQ羣:857662006 尋找有志同道合的小夥伴,互幫互助, 羣裏還有不錯的視頻學習教程和PDF電子書! '''
class Singleton(object):
def __new__(cls):
# 關鍵在於這,每一次實例化的時候,咱們都只會返回這同一個instance對象
if not hasattr(cls, 'instance'):
cls.instance = super(Singleton, cls).__new__(cls)
return cls.instance
obj1 = Singleton()
obj2 = Singleton()
obj1.attr1 = 'value1'
print obj1.attr1, obj2.attr1
print obj1 is obj2
複製代碼
輸出結果:
value1 value1
True
複製代碼
能夠看到obj1和obj2是同一個實例。
''' 遇到問題沒人解答?小編建立了一個Python學習交流QQ羣:857662006 尋找有志同道合的小夥伴,互幫互助, 羣裏還有不錯的視頻學習教程和PDF電子書! '''
class A(object):
def __init__(self):
print "init"
def __new__(cls,*args, **kwargs):
print "new %s"%cls
return object.__new__(cls, *args, **kwargs)
A()
複製代碼
輸出:
new <class '__main__.A'>
init
複製代碼
知識點:
繼承自object的新式類纔有__new__
__new__至少要有一個參數cls,表明要實例化的類,此參數在實例化時由Python解釋器自動提供
__new__必需要有返回值,返回實例化出來的實例,這點在本身實現__new__時要特別注意,能夠return父類__new__出來的實例,或者直接是object的__new__出來的實例
__init__有一個參數self,就是這個__new__返回的實例,__init__在__new__的基礎上能夠完成一些其它初始化的動做,__init__不須要返回值
若__new__沒有正確返回當前類cls的實例,那__init__是不會被調用的,即便是父類的實例也不行
''' 遇到問題沒人解答?小編建立了一個Python學習交流QQ羣:857662006 尋找有志同道合的小夥伴,互幫互助, 羣裏還有不錯的視頻學習教程和PDF電子書! '''
class A(object):
pass
class B(A):
def __init__(self):
print "init"
def __new__(cls,*args, **kwargs):
print "new %s"%cls
return object.__new__(A, *args, **kwargs)
b=B()
print type(b)
複製代碼
輸出:
new <class '__main__.B'>
<class '__main__.A'>
複製代碼