Python 面向對象編程容易忽視的知識點
類既可以很簡單,也可以很復雜。最簡單的情況,類僅用作名稱空間,這意味著你把數據保存在變量中,對他們按照名稱空間進行分組,使他們出入同樣的關系空間中。這樣的類僅作為容器對象來共享名字空間。
1. __init__(self,...)‘構造器’方法
__init__(self,...)方法實際上并不是一個構造器,其并沒有創造一個新的對象,Python通過函數操作符()創建對象。在解釋器創建一個實例后,最先調用__init__(self,...)方法,定義額外的行為,如果沒有定義或者覆蓋__init__(self,...)方法,對實例不會施加任何特別的操作,直接返回它的對象,實例化過程完畢。函數的返回值應當為None,如果返回來任意對象,會導致TypeError異常。
class ReturnInt:
def __init__(self):
return 1
ri=ReturnInt()
Traceback (most recent call last):
File "C:/Users/PycharmProjects/untitled/Study EXP/Q.py", line 5, in <module>
ri=ReturnInt()
TypeError: __init__() should return None
重寫子類的__init__(self,...)方法不會自動調用基類的__init__(self,...)。所以如果需要在子類中調用基類的__init__(self,...),需要明確指出。
class C(P):
def __init__(self):
P.__init__(self)
我們可以使用super()函數更方便高效的重寫上面的代碼:
class C(P):
def __init__(self):
super(C,self).__init__()
不需要提供明確的父類,super()函數會幫助我們找到相應的父類,然后方便調用相關的屬性。
2. __new__(cls,...)‘構造器’方法
調用__new__(cls,...)時,實例不一定已經被創建,與__init__(self,...)方法需要傳入實例的引用不同,__new__(cls,...)傳入當前類的引用。可以用來對內建類型進行派生,實例化不可變對象。
3. 類屬性
類屬性僅與其被定義的的類相綁定,主要包括數據屬性(靜態變量)和方法。方法在類中定義,但卻只能被實例調用。如果沒有與類的數據屬性同名的實例屬性,通過實例也可以訪問類的數據屬性,但是卻不能作修改。
特殊的類屬性:
C.__name__ 類C的名字(字符串)
C.__doc__ 類C的文檔字符串
C.__bases__ 類C的所有父類構成的元組
C.__dict__ 類C的屬性
C.__module__ 類C定義所在的模塊
C.__class__ 實例C對應的類
4. 實例屬性
實例僅擁有數據屬性,即類屬性。實例屬性可以動態創建,但是如果屬性在條件語句中創建,而該條件語句未執行,則該屬性實際并不存在,如果在后面代碼訪問該屬性,就會出錯。
帶默認參數的__init__(self,...)可以更有效的初始化一個實例,這樣可以省去顯式傳值的麻煩,但是默認參數應當是不變的對象,在使用入列表和字典等可變對象時應時刻保持警惕。
class demo_list:
def __init__(self, l=[]):
self.l = l
def add(self, ele):
self.l.append(ele)
def appender(ele):
obj = demo_list()
obj.add(ele)
print obj.lif
__name__ == "__main__":
for i in range(5):
appender(i)
[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3, 4]
因為默認參數只會計算一次,不會重復使用,在上面的例子中,雖然使用不同的新建實例,可因為構造器的參數使用的是對列表的引用作為默認參數,所以每次的實例屬性都指向該列表所在的空間。
點擊查看更多相關資料
使用內建函數dir()可以顯示類和實例屬性,實例具有__dict__的特殊屬性,該屬性由字典組成,包含一個實例的所有屬性。
'#的意思為,當ReturnInt為新式類時,dir對應的結果'
class ReturnInt: #class ReturnInt(object):
def __init__(self):
pass
ri=ReturnInt()
ri.name='a'
ri.age=10
print ri.__dict__
print dir(ri)
{'age': 10, 'name': 'a'}
['__doc__', '__init__', '__module__', 'age', 'name']
#['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name']
從上面的程序中可以看到除了我們添加的實例屬性,實例還有許多其他的屬性,這些屬性是實例的內建類型屬性。
5. 綁定和方法調用
類屬性之一的方法只有在其所屬的類擁有實例時,才能被調用,當存在一個實例時,方法才被認為是綁定到那個實例了,沒有實例時,方法就是未綁定的。
當類具有實例時,比如類MyClass,通過mc.foo()調用可以把mc即self自動傳入到foo()中,而不需要我們明確的寫為mc.foo(self)。當時當沒有一個實例并且需要調用一個非綁定的方法時就必須傳遞self參數。
文/CinderellaM(簡書)