Python從菜鳥到高手(18):類與方法的私有化

1. 建立本身的類

學習面向對象的第一步,就是建立一個類。由於類是面向對象的基石。Python類和其餘編程語言(Java、C#等)的類差很少,也須要使用class關鍵字。下面經過一個實際的例子來看一下Python類是如何建立的。html

本例會建立一個類,以及利用這個類建立兩個對象,並調用其中的方法。編程

 1 # 建立一個Person類
 2 class Person:
 3     # 定義setName方法
 4     def setName(self, name):
 5         self.name = name
 6     # 定義getName方法
 7     def getName(self):
 8         return self.name
 9     # 定義greet方法
10     def greet(self):
11         print("Hello, I'm {name}.".format(name = self.name))
12 
13 # 建立Person對象
14 person1 = Person()
15 # 建立Person對象
16 person2 = Person()
17 # 調用person1對象的setName方法
18 person1.setName("Bill Gates")
19 # 調用person2對象的name屬性
20 person2.name = "Bill Clinton"
21 # 調用person1對象的getName方法
22 print(person1.getName())
23 # 調用person1對象的greet方法
24 person1.greet()
25 # 調用person2對象的屬性
26 print(person2.name)
27 # 調用person2對象的greet方法,另一種調用方法的方式
28 Person.greet(person2)

 

程序運行結果以下圖所示。編程語言

image.png

從上面的代碼咱們能夠了解到Python類的以下知識點。編輯器

  • Python類使用class關鍵字定義,類名直接跟在class關鍵字的後面。
  • 類也是一個代碼塊,因此類名後面要跟着一個冒號(:)。
  • 類中的方法其實就是函數,定義的方法也徹底同樣,只是因爲函數定義在類的內部,因此爲了區分,將定義在類內部的函數稱爲方法。
  • 咱們能夠看到,每個方法的第1個參數都是self,其實這是必須的。這個參數名不必定叫self(能夠叫abc或任何其餘名字),但任意一個方法必須至少指定一個self參數,若是方法中包含多個參數,第1個參數將做爲self參數使用。在調用方法時,這個參數的值不須要本身傳遞,系統會將方法所屬的對象傳入這個參數。在方法內部能夠利用這個參數調用對象自己的資源,如屬性、方法等。
  • 經過self參數添加的name變量是Person類的屬性,能夠在外部訪問。本例設置了person2對象的name屬性的值,與調用person2.setName方法的效果徹底相同。
  • 使用類建立對象的方式與調用函數的方式相同。在Python語言中,不須要像Java同樣使用new關鍵字建立對象,只須要用類名加上構造方法(在後面的章節會詳細介紹)參數值便可。
  • 調用對象的方法有兩種方式,一種是直接經過對象變量調用方法,另外一種是經過類調用方法,而且將相應的對象傳入方法的第1個參數。在本例中使用了Person.greet(person2)的方式調用了person2對象中的greet方法。

若是使用集成開發環境,如PyDev、PyCharm,那麼代碼編輯器也會對面向對象有很好的支持,例如,當在對象變量後輸入一個點(.)後,IDE會爲咱們列出該對象中全部能夠調用的資源,包括方法和屬性,以下圖所示。函數

image.png

2.方法和私有化

Python類默認狀況下,全部的方法均可以被外部訪問。不過像不少其餘編程語言,如Java、C#等,都提供了private關鍵字將方法私有化,也就是說只有類的內部方法才能訪問私有化的方法,經過正常的方式是沒法訪問對象的私有化方法的(除非使用反射技術,這就另當別論了)。不過在Python類中並無提供private或相似的關鍵字將方法私有化,但能夠曲線救國。學習

在Python類的方法名前面加雙下劃線(__)可讓該方法在外部不可訪問。spa

 1 class Person:
 2     # method1方法在類的外部能夠訪問
 3     def method1(self):
 4         print("method1")
 5     # __method2方法在類的外部不可訪問
 6     def __method2(self):
 7         print("method2")
 8 
 9 p = Person()
10 p.method1()
11 p.__method2()       # 拋出異常

 

若是執行上面的代碼,會拋出以下圖所示的異常信息,緣由是調用了私有化方法method2。code

image.png

其實「method2」方法也不是絕對不可訪問。Python編譯器在編譯Python源代碼時並無將「method2」方法真正私有化,而是一旦遇到方法名以雙下劃線(__)開頭的方法,就會將方法名改爲「ClassNamemethodName」的形式。其中ClassName表示該方法所在的類名,「methodName」表示方法名。ClassName前面要加上但單下劃線()前綴。orm

對於上面的代碼,Python編譯器會將「method2」方法改名爲「_Personmethod2」,因此在類的外部調用「method2」方法會拋出異常。拋出異常的緣由並非「method2」方法被私有化了,而是Python編譯器把「method2」的名稱改成「_Personmethod2」了。當咱們瞭解了這些背後的原理,就能夠經過調用「_Personmethod2」方法來執行「method2」方法。htm

1 p = Person()
2 p._Person__method2()        # 正常調用「__method2」方法

 

本例會建立一個MyClass類,並定義兩個公共的方法(getName和setName)和一個私有的方法(outName)。而後建立了MyClass類的實例,並調用了這些方法。爲了證實Python編譯器在編譯MyClass類時作了手腳,本例還使用了inspect模塊中的getmembers函數獲取MyClass類中全部的成員方法,並輸出方法名。很顯然,「outName」被改爲了「_MyClass__outName」。

 1 class MyClass:
 2     # 公共方法
 3     def getName(self):
 4         return self.name
 5     # 公共方法
 6     def setName(self, name):
 7         self.name = name
 8         # 在類的內部能夠直接調用私有方法
 9         self.__outName()
10     # 私有方法    
11     def __outName(self):
12         print("Name = {}".format(self.name))        
13 
14 myClass = MyClass()
15 # 導入inspect模塊
16 import inspect
17 # 獲取MyClass類中全部的方法
18 methods = inspect.getmembers(myClass, predicate=inspect.ismethod)
19 print(methods)
20 # 輸出類方法的名稱
21 for method in methods:
22     print(method[0])
23 print("------------")
24 # 調用setName方法
25 myClass.setName("Bill")
26 # 調用getName方法
27 print(myClass.getName())
28 # 調用「__outName」方法,這裏調用了改完名後的方法,因此能夠正常執行
29 myClass._MyClass__outName()
30 # 拋出異常,由於「__outName」方法在MyClass類中並不存在
31 print(myClass.__outName())

 

程序運行結果以下圖所示。

image.png

image

從getmembers函數列出的MyClass類方法的名字能夠看出,「_MyClassoutName」被綁定到了「outName」方法上,咱們能夠將「_MyClassoutName」看作是「outName」的一個別名,一旦爲某個方法起了別名,那麼原來的名字在類外部就不可用了。MyClass類中的getName方法和setName方法的別名和原始方法名相同,因此在外部能夠直接調用getName和setName方法。

相關文章
相關標籤/搜索