天天看點

python類的方法

在一個類中,可能出現三種方法,執行個體方法、靜态方法和類方法,下面來看看三種方法的不同。

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