Python 面向對象編程容易忽視的知識點

gu311711 8年前發布 | 24K 次閱讀 Python Python開發

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(簡書)

 本文由用戶 gu311711 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!