標籤:建立 person art 對象 需要 nbsp strong 定義 style
1、python中建立類屬性
類是模板,而執行個體則是根據類建立的對象。
綁定在一個執行個體上的屬性不會影響其他執行個體,但是,類本身也是一個對象,如果在類上綁定一個屬性,則所有執行個體都可以訪問類的屬性,並且,所有執行個體訪問的類屬性都是同一個!也就是說,執行個體屬性每個執行個體各自擁有,互相獨立,而類屬性有且只有一份。
定義類屬性可以直接在 class 中定義:
class Person(object): address = ‘Earth‘ def __init__(self, name): self.name = name
因為類屬性是直接綁定在類上的,所以,訪問類屬性不需要建立執行個體,就可以直接存取:
print Person.address# => Earth
對一個執行個體調用類的屬性也是可以訪問的,所有執行個體都可以訪問到它所屬的類的屬性:
p1 = Person(‘Bob‘)p2 = Person(‘Alice‘)print p1.address# => Earthprint p2.address# => Earth
由於Python是動態語言,類屬性也是可以動態添加和修改的:
Person.address = ‘China‘print p1.address# => ‘China‘print p2.address# => ‘China‘
因為類屬性只有一份,所以,當Person類的address改變時,所有執行個體訪問到的類屬性都改變了。
2、python中類屬性和執行個體屬性名稱字衝突怎麼辦
修改類屬性會導致所有執行個體訪問到的類屬性全部都受影響,但是,如果在執行個體變數上修改類屬性會發生什麼問題呢?
class Person(object): address = ‘Earth‘ def __init__(self, name): self.name = namep1 = Person(‘Bob‘)p2 = Person(‘Alice‘)print ‘Person.address = ‘ + Person.addressp1.address = ‘China‘print ‘p1.address = ‘ + p1.addressprint ‘Person.address = ‘ + Person.addressprint ‘p2.address = ‘ + p2.address
結果如下:
Person.address = Earthp1.address = ChinaPerson.address = Earthp2.address = Earth
我們發現,在設定了 p1.address = ‘China‘ 後,p1訪問 address 確實變成了 ‘China‘,但是,Person.address和p2.address仍然是‘Earch‘,怎麼回事?
原因是 p1.address = ‘China‘並沒有改變 Person 的 address,而是給 p1這個執行個體綁定了執行個體屬性address ,對p1來說,它有一個執行個體屬性address(值是‘China‘),而它所屬的類Person也有一個類屬性address,所以:
訪問 p1.address 時,優先尋找執行個體屬性,返回‘China‘。
訪問 p2.address 時,p2沒有執行個體屬性address,但是有類屬性address,因此返回‘Earth‘。
可見,當執行個體屬性和類屬性重名時,執行個體屬性優先順序高,它將屏蔽掉對類屬性的訪問。
當我們把 p1 的 address 執行個體屬性刪除後,訪問 p1.address 就又返回類屬性的值 ‘Earth‘了:
del p1.addressprint p1.address# => Earth
可見,千萬不要在執行個體上修改類屬性,它實際上並沒有修改類屬性,而是給執行個體綁定了一個執行個體屬性。
3、python中定義執行個體方法
一個執行個體的私人屬性就是以__開頭的屬性,無法被外部存取,那這些屬性定義有什麼用?
雖然私人屬性無法從外部存取,但是,從類的內部是可以訪問的。除了可以定義執行個體的屬性外,還可以定義執行個體的方法。
執行個體的方法就是在類中定義的函數,它的第一個參數永遠是 self,指向調用該方法的執行個體本身,其他參數和一個普通函數是完全一樣的:
class Person(object): def __init__(self, name): self.__name = name def get_name(self): return self.__name
get_name(self) 就是一個執行個體方法,它的第一個參數是self。__init__(self, name)其實也可看做是一個特殊的執行個體方法。
調用執行個體方法必須在執行個體上調用:
p1 = Person(‘Bob‘)print p1.get_name() # self不需要顯式傳入# => Bob
在執行個體方法內部,可以訪問所有執行個體屬性,這樣,如果外部需要訪問私人屬性,可以通過方法調用獲得,這種資料封裝的形式除了能保護內部資料一致性外,還可以簡化外部調用的難度.
練習:
請給 Person 類增加一個私人屬性 __score,表示分數,再增加一個執行個體方法 get_grade(),能根據 __score 的值分別返回 A-優秀, B-及格, C-不及格三檔。
# -*- coding:utf-8-*-class Person(object): def __init__(self, name, score): self.__name=name self.__score=score def get_grade(self): if self.__score>=80: return "A-優秀" elif self.__score>=60: return "B-及格" return "C-不及格"p1 = Person(‘Bob‘, 90)p2 = Person(‘Alice‘, 65)p3 = Person(‘Tim‘, 48)print p1.get_grade()print p2.get_grade()print p3.get_grade()
4、python中方法也是屬性
我們在 class 中定義的執行個體方法其實也是屬性,它實際上是一個函數對象:
class Person(object): def __init__(self, name, score): self.name = name self.score = score def get_grade(self): return ‘A‘p1 = Person(‘Bob‘, 90)print p1.get_grade# => <bound method Person.get_grade of <__main__.Person object at 0x109e58510>>print p1.get_grade()# => A
也就是說,p1.get_grade 返回的是一個函數對象,但這個函數是一個綁定到執行個體的函數,p1.get_grade() 才是方法調用。
因為方法也是一個屬性,所以,它也可以動態地添加到執行個體上,只是需要用 types.MethodType() 把一個函數變為一個方法:
import typesdef fn_get_grade(self): if self.score >= 80: return ‘A‘ if self.score >= 60: return ‘B‘ return ‘C‘class Person(object): def __init__(self, name, score): self.name = name self.score = scorep1 = Person(‘Bob‘, 90)p1.get_grade = types.MethodType(fn_get_grade, p1, Person)print p1.get_grade()# => Ap2 = Person(‘Alice‘, 65)print p2.get_grade()# ERROR: AttributeError: ‘Person‘ object has no attribute ‘get_grade‘
# 因為p2執行個體並沒有綁定get_grade
給一個執行個體動態添加方法並不常見,直接在class中定義要更直觀。
python物件導向