在一個類中,可能出現三種方法,執行個體方法、靜态方法和類方法,下面來看看三種方法的不同。
1)執行個體方法
執行個體方法的第一個參數必須是”self”,”self”類似于C++中的”this”。
執行個體方法隻能通過類執行個體進行調用,這時候”self”就代表這個類執行個體本身。通過”self”可以直接通路執行個體的屬性。
例如:
>>> class Student(object):
... count = 0
... books = []
... def __init__(self,name,age):
... self.name = name
... self.age = age
... def printInstanceInfo(self):
... print "%s is %d years old" %(self.name,self.age)
... pass
...
>>> walber = Student("Wilber",28) ##執行個體調用
>>> walber.printInstanceInfo()
Wilber is 28 years old
2)類方法
類方法以cls作為第一個參數,cls表示類本身,定義時使用@classmethod裝飾器。通過cls可以通路類的相關屬性。
... '''
... this is a Student class
... count = 0
... books = []
... def __init__(self, name, age):
... self.name = name
... self.age = age
...
... @classmethod
... def printClassInfo(cls):
... print cls.__name__
... print dir(cls)
... pass
代碼調用的輸出為如下:
>>> Student.printClassInfo() ##通過類名通路
Student
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'books', 'count', 'printClassInfo']
>>> wilber = Student("Wilber", 28)
>>> wilber.printClassInfo() ##通過執行個體通路
從這段代碼可以看到,類方法可以通過類名通路,也可以通過執行個體通路。
3)靜态方法
與執行個體方法和類方法不同,靜态方法沒有參數限制,既不需要執行個體參數,也不需要類參數,定義的時候使用@staticmethod裝飾器。
同類方法一樣,靜态法可以通過類名通路,也可以通過執行個體通路。
例如:
... @staticmethod
... def printClassAttr():
... print Student.count
... print Student.books
>>> Student.printClassAttr()
[]
>>> wilber.printClassAttr()
總結:
這三種方法的主要差別在于參數,執行個體方法被綁定到一個執行個體,隻能通過執行個體進行調用; 但是對于靜态方法和類方法,可以通過類名和執行個體兩種方式進行調用。
二、通路控制
Python中沒有通路控制的關鍵字,例如private、protected等等。但是,在Python編碼中,有一些約定來進行通路控制。
a. 單下劃線”_”
在Python中,通過單下劃線”_”來實作子產品級别的私有化,一般約定以單下劃線”_”開頭的變量、函數為子產品私有的,也就是說”from moduleName import *”将不會引入以單下劃線”_”開頭的變量、函數。
現在有一個子產品lib.py,内容用如下,子產品中一個變量名和一個函數名分别以”_”開頭:
numA = 10
_numA = 100
def printNum():
print "numA is:", numA
print "_numA is:", _numA
def _printNum():
當通過下面代碼引入lib.py這個子產品後,所有的以”_”開頭的變量和函數都沒有被引入,如果通路将會抛出異常:
from lib import *
print numA
printNum()
print _numA
#print _printNum()
b. 雙下劃線”__”
對于Python中的類屬性,可以通過雙下劃線”__”來實作一定程度的私有化,因為雙下劃線開頭的屬性在運作時會被”混淆”(mangling)。
在Student類中,加入了一個”__address”屬性:
class Student(object):
def __init__(self, name, age):
self.name = name
self.age = age
self.__address = "Shanghai"
pass
wilber = Student("Wilber", 28)
print wilber.__address
當通過執行個體wilber通路這個屬性的時候,就會得到一個異常,提示屬性”__address”不存在。
其實,通過内建函數dir()就可以看到其中的一些原由,”__address”屬性在運作時,屬性名被改為了”_Student__address”(屬性名前增加了單下劃線和類名)
>>> dir(wilber)
['_Student__address', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '
__subclasshook__', '__weakref__', 'age', 'name']
是以說,即使是雙下劃線,也沒有實作屬性的私有化,因為通過下面的方式還是可以直接通路”__address”屬性:
>>> print wilber._Student__address
Shanghai
>>>
雙下劃線的另一個重要的目地是,避免子類對父類同名屬性的沖突。
看下面的一個例子:
>>> class A(object):
... def __init__(self):
... self.__private()
... self.public()
... def __private(self):
... print 'A.__private()'
... def public(self):
... print 'A.public()'
>>> class B(A):
... print 'B.__private()'
... print 'B.public()'
>>> b = B()
當執行個體化B的時候,由于沒有定義__init__函數,将調用父類的__init__,但是由于雙下劃線的”混淆”效果,”self.__private()”将變成 “self._A__private()”。
輸出如下内容:
A.__private()
B.public()
“_”和” __”的使用 更多的是一種規範/約定,并沒有真正達到限制的目的:
“_”:以單下劃線開頭表示的是protected類型的變量,即隻能允許其本身與子類進行通路;同時表示弱内部變量标示,如,當使用”from moduleNmae import *”時,不會将以一個下劃線開頭的對象引入。
“__”:雙下劃線的表示的是私有類型的變量。隻能是允許這個類本身進行通路了,連子類也不可以,這類屬性在運作時屬性名會加上單下劃線和類名。
版權聲明:原創作品,如需轉載,請注明出處。否則将追究法律責任
本文轉自 鵬愛 51CTO部落格,原文連結:http://blog.51cto.com/pengai/1927470