面向?qū)ο缶幊袒A(chǔ)-Python類(一)

python中創(chuàng)建實(shí)例屬性

雖然可以通過Person類創(chuàng)建出xiaoming颊艳、xiaohong等實(shí)例丧靡,但是這些實(shí)例看上除了地址不同外,沒有什么其他不同籽暇。在現(xiàn)實(shí)世界中,區(qū)分xiaoming饭庞、xiaohong要依靠他們各自的名字戒悠、性別、生日等屬性舟山。

如何讓每個(gè)實(shí)例擁有各自不同的屬性绸狐?由于Python是動(dòng)態(tài)語(yǔ)言卤恳,對(duì)每一個(gè)實(shí)例,都可以直接給他們的屬性賦值寒矿,例如亮元,給xiaoming這個(gè)實(shí)例加上name募书、gender和birth屬性:

    xiaoming = Person()
    xiaoming.name = 'Xiao Ming'
    xiaoming.gender = 'Male'
    xiaoming.birth = '1990-1-1'

給xiaohong加上的屬性不一定要和xiaoming相同:

xiaohong = Person()
xiaohong.name = 'Xiao Hong'
xiaohong.school = 'No. 1 High School'
xiaohong.grade = 2

實(shí)例的屬性可以像普通變量一樣進(jìn)行操作:

xiaohong.grade = xiaohong.grade + 1

列子:

請(qǐng)創(chuàng)建包含兩個(gè) Person 類的實(shí)例的 list,并給兩個(gè)實(shí)例的 name 賦值,然后按照 name 進(jìn)行排序卖局。

    class Person(object):
        pass
    
    p1 = Person()
    p1.name = 'Bart'
    
    p2 = Person()
    p2.name = 'Adam'
    
    p3 = Person()
    p3.name = 'Lisa'
    
    L1 = [p1, p2, p3]
    L2 = sorted(L1,lambda p1,p2:cmp(p1.name,p2.name))
    
    print L2[0].name
    print L2[1].name
    print L2[2].name

python中初始化實(shí)例屬性

雖然我們可以自由地給一個(gè)實(shí)例綁定各種屬性,但是辈灼,現(xiàn)實(shí)世界中甫匹,一種類型的實(shí)例應(yīng)該擁有相同名字的屬性。例如蓝牲,Person類應(yīng)該在創(chuàng)建的時(shí)候就擁有name趟脂、genderbirth屬性,怎么辦例衍?

在定義 Person 類時(shí)昔期,可以為Person類添加一個(gè)特殊的init()方法,當(dāng)創(chuàng)建實(shí)例時(shí)佛玄,init()方法被自動(dòng)調(diào)用硼一,我們就能在此為每個(gè)實(shí)例都統(tǒng)一加上以下屬性:

    class Person(object):
        def __init__(self, name, gender, birth):
            self.name = name
            self.gender = gender
            self.birth = birth

init() 方法的第一個(gè)參數(shù)必須是 self(也可以用別的名字,但建議使用習(xí)慣用法)翎嫡,后續(xù)參數(shù)則可以自由指定欠动,和定義函數(shù)沒有任何區(qū)別。

相應(yīng)地惑申,創(chuàng)建實(shí)例時(shí)具伍,就必須要提供除 self以外的參數(shù):

    xiaoming = Person('Xiao Ming', 'Male', '1991-1-1')
    xiaohong = Person('Xiao Hong', 'Female', '1992-2-2')

有了init()方法,每個(gè)Person實(shí)例在創(chuàng)建時(shí)圈驼,都會(huì)有name人芽、genderbirth這3個(gè)屬性,并且绩脆,被賦予不同的屬性值萤厅,訪問屬性使用.操作符:

print xiaoming.name
# 輸出 'Xiao Ming'
print xiaohong.birth
# 輸出 '1992-2-2'

要特別注意的是,初學(xué)者定義init()方法常常忘記了 self 參數(shù):

>>> class Person(object):
...     def __init__(name, gender, birth):
...         pass
... 
>>> xiaoming = Person('Xiao Ming', 'Male', '1990-1-1')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() takes exactly 3 arguments (4 given)

這會(huì)導(dǎo)致創(chuàng)建失敗或運(yùn)行不正常靴迫,因?yàn)榈谝粋€(gè)參數(shù)name被Python解釋器傳入了實(shí)例的引用惕味,從而導(dǎo)致整個(gè)方法的調(diào)用參數(shù)位置全部沒有對(duì)上。

例子:

要定義關(guān)鍵字參數(shù)玉锌,使用**kw名挥;

除了可以直接使用self.name = 'xxx'設(shè)置一個(gè)屬性外,還可以通過 setattr(self, 'name', 'xxx') 設(shè)置屬性主守。

參考代碼:

    class Person(object):
        def __init__(self, name, gender, birth, **kw):
            self.name = name
            self.gender = gender
            self.birth = birth
            for k, v in kw.iteritems():
                setattr(self, k, v)
    xiaoming = Person('Xiao Ming', 'Male', '1990-1-1', job='Student')
    print xiaoming.name
    print xiaoming.job

python中訪問限制

Python對(duì)屬性權(quán)限的控制是通過屬性名來實(shí)現(xiàn)的禀倔,如果一個(gè)屬性由雙下劃線開頭(__)榄融,該屬性就無法被外部訪問【群看例子:

class Person(object):
    def __init__(self, name):
        self.name = name
        self._title = 'Mr'
        self.__job = 'Student'
p = Person('Bob')
print p.name
# => Bob
print p._title
# => Mr
print p.__job
# => Error
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute '__job'

可見愧杯,只有以雙下劃線開頭的"__job"不能直接被外部訪問。

但是鞋既,如果一個(gè)屬性以"__xxx__"的形式定義力九,那它又可以被外部訪問了,以"__xxx__"定義的屬性在Python的類中被稱為特殊屬性涛救,有很多預(yù)定義的特殊屬性可以使用畏邢,通常我們不要把普通屬性用"__xxx__"定義。

單下劃線開頭的屬性"_xxx"雖然也可以被外部訪問检吆,但是舒萎,按照習(xí)慣,他們不應(yīng)該被外部訪問蹭沛。

例子:

class Person(object):
    def __init__(self, name, score):
        self.name = name
        self.__score = score

p = Person('Bob', 59)

print p.name
print p.__score

運(yùn)行結(jié)果:

Traceback (most recent call last):
  File "index.py", line 9, in 
    print p.__score
AttributeError: 'Person' object has no attribute '__score'
Bob

python中創(chuàng)建類屬性

類是模板臂寝,而實(shí)例則是根據(jù)類創(chuàng)建的對(duì)象。

綁定在一個(gè)實(shí)例上的屬性不會(huì)影響其他實(shí)例摊灭,但是咆贬,類本身也是一個(gè)對(duì)象,如果在類上綁定一個(gè)屬性帚呼,則所有實(shí)例都可以訪問類的屬性掏缎,并且,所有實(shí)例訪問的類屬性都是同一個(gè)煤杀!也就是說眷蜈,實(shí)例屬性每個(gè)實(shí)例各自擁有,互相獨(dú)立沈自,而類屬性有且只有一份.

定義類屬性可以直接在 class 中定義:

class Person(object):
    address = 'Earth'
    def __init__(self, name):
        self.name = name

因?yàn)轭悓傩允侵苯咏壎ㄔ陬惿系淖萌澹裕L問類屬性不需要?jiǎng)?chuàng)建實(shí)例枯途,就可以直接訪問:

print Person.address
# => Earth

對(duì)一個(gè)實(shí)例調(diào)用類的屬性也是可以訪問的忌怎,所有實(shí)例都可以訪問到它所屬的類的屬性:

p1 = Person('Bob')
p2 = Person('Alice')
print p1.address
# => Earth
print p2.address
# => Earth

由于Python是動(dòng)態(tài)語(yǔ)言,類屬性也是可以動(dòng)態(tài)添加和修改的:

Person.address = 'China'
print p1.address
# => 'China'
print p2.address
# => 'China'

因?yàn)轭悓傩灾挥幸环堇乙模粤裥ィ?dāng)Person類的address改變時(shí),所有實(shí)例訪問到的類屬性都改變了晚岭。

例子:
請(qǐng)給Person 類添加一個(gè)類屬性 count插掂,每創(chuàng)建一個(gè)實(shí)例,count 屬性就加 1,這樣就可以統(tǒng)計(jì)出一共創(chuàng)建了多少個(gè) Person 的實(shí)例辅甥。
由于創(chuàng)建實(shí)例必定會(huì)調(diào)用__init__()方法,所以在這里修改類屬性 count 很合適燎竖。

參考代碼:

class Person(object):
    count = 0
    def __init__(self, name):
        Person.count = Person.count + 1
        self.name = name
p1 = Person('Bob')
print Person.count
# => 1
p2 = Person('Alice')
print Person.count
# => 2
p3 = Person('Tim')
print Person.count
# => 3

python中類屬性和實(shí)例屬性名字沖突怎么辦

修改類屬性會(huì)導(dǎo)致所有實(shí)例訪問到的類屬性全部都受影響璃弄,但是,如果在實(shí)例變量上修改類屬性會(huì)發(fā)生什么問題呢构回?

class Person(object):
    address = 'Earth'
    def __init__(self, name):
        self.name = name

p1 = Person('Bob')
p2 = Person('Alice')

print 'Person.address = ' + Person.address

p1.address = 'China'
print 'p1.address = ' + p1.address

print 'Person.address = ' + Person.address
print 'p2.address = ' + p2.address

結(jié)果如下:

Person.address = Earth
p1.address = China
Person.address = Earth
p2.address = Earth

我們發(fā)現(xiàn)夏块,在設(shè)置了p1.address = 'China'后,p1訪問 address 確實(shí)變成了 'China'纤掸,但是脐供,Person.address和p2.address仍然是'Earch',怎么回事借跪?

原因是 p1.address = 'China'并沒有改變 Person 的 address政己,而是給p1這個(gè)實(shí)例綁定了實(shí)例屬性address,對(duì)p1來說掏愁,它有一個(gè)實(shí)例屬性address(值是'China')歇由,而它所屬的類Person也有一個(gè)類屬性address,所以:

訪問p1.address時(shí)果港,優(yōu)先查找實(shí)例屬性沦泌,返回'China'。

訪問 p2.address 時(shí)辛掠,p2沒有實(shí)例屬性address谢谦,但是有類屬性address,因此返回'Earth'萝衩。

可見回挽,當(dāng)實(shí)例屬性和類屬性重名時(shí),實(shí)例屬性優(yōu)先級(jí)高欠气,它將屏蔽掉對(duì)類屬性的訪問。

當(dāng)我們把 p1 的 address 實(shí)例屬性刪除后预柒,訪問 p1.address 就又返回類屬性的值 'Earth'了:

del p1.address
print p1.address
# => Earth

可見,千萬不要在實(shí)例上修改類屬性宜鸯,它實(shí)際上并沒有修改類屬性,而是給實(shí)例綁定了一個(gè)實(shí)例屬性淋袖。

列子:
請(qǐng)把上節(jié)的 Person 類屬性 count 改為 __count鸿市,再試試能否從實(shí)例和類訪問該屬性。

class Person(object):
    __count = 0
    def __init__(self, name):
        Person.__count = Person.__count + 1
        self.name = name
        print Person.__count

p1 = Person('Bob')
p2 = Person('Alice')

print Person.__count

python中定義實(shí)例方法

一個(gè)實(shí)例的私有屬性就是以__開頭的屬性焰情,無法被外部訪問,那這些屬性定義有什么用内舟?

雖然私有屬性無法從外部訪問合敦,但是,從類的內(nèi)部是可以訪問的验游。除了可以定義實(shí)例的屬性外充岛,還可以定義實(shí)例的方法耕蝉。

實(shí)例的方法就是在類中定義的函數(shù),它的第一個(gè)參數(shù)永遠(yuǎn)是 self蒜魄,指向調(diào)用該方法的實(shí)例本身爪膊,其他參數(shù)和一個(gè)普通函數(shù)是完全一樣的:

class Person(object):

    def __init__(self, name):
        self.__name = name

    def get_name(self):
        return self.__name

get_name(self)就是一個(gè)實(shí)例方法,它的第一個(gè)參數(shù)是self推盛。__init__(self, name)其實(shí)也可看做是一個(gè)特殊的實(shí)例方法。

調(diào)用實(shí)例方法必須在實(shí)例上調(diào)用

p1 = Person('Bob')
print p1.get_name()  # self不需要顯式傳入
# => Bob

在實(shí)例方法內(nèi)部榔昔,可以訪問所有實(shí)例屬性瘪菌,這樣,如果外部需要訪問私有屬性诵肛,可以通過方法調(diào)用獲得默穴,這種數(shù)據(jù)封裝的形式除了能保護(hù)內(nèi)部數(shù)據(jù)一致性外,還可以簡(jiǎn)化外部調(diào)用的難度蓄诽。

列子:
請(qǐng)給 Person 類增加一個(gè)私有屬性 __score仑氛,表示分?jǐn)?shù)闸英,再增加一個(gè)實(shí)例方法 get_grade(),能根據(jù) __score 的值分別返回 A-優(yōu)秀, B-及格, C-不及格三檔甫何。

class Person(object):

    def __init__(self, name, score):
        self.__name = name
        self.__score = score

    def get_grade(self):
        if self.__score >= 80:
            return 'A'
        if 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()

python中方法也是屬性

我們?cè)?class 中定義的實(shí)例方法其實(shí)也是屬性米酬,它實(shí)際上是一個(gè)函數(shù)對(duì)象:

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 返回的是一個(gè)函數(shù)對(duì)象,但這個(gè)函數(shù)是一個(gè)綁定到實(shí)例的函數(shù)跳芳,p1.get_grade()才是方法調(diào)用竹勉。

因?yàn)榉椒ㄒ彩且粋€(gè)屬性,所以次乓,它也可以動(dòng)態(tài)地添加到實(shí)例上,只是需要用types.MethodType() 把一個(gè)函數(shù)變?yōu)橐粋€(gè)方法:

import types
def 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 = score

p1 = Person('Bob', 90)
p1.get_grade = types.MethodType(fn_get_grade, p1, Person)
print p1.get_grade()
# => A
p2 = Person('Alice', 65)
print p2.get_grade()
# ERROR: AttributeError: 'Person' object has no attribute 'get_grade'
# 因?yàn)閜2實(shí)例并沒有綁定get_grade

python中定義類方法

屬性類似城看,方法也分實(shí)例方法類方法杏慰。

class中定義的全部是實(shí)例方法,實(shí)例方法第一個(gè)參數(shù)self是實(shí)例本身轰胁。

要在class中定義類方法朝扼,需要這么寫:

class Person(object):
    count = 0
    @classmethod
    def how_many(cls):
        return cls.count
    def __init__(self, name):
        self.name = name
        Person.count = Person.count + 1

print Person.how_many()
p1 = Person('Bob')
print Person.how_many()

通過標(biāo)記一個(gè) @classmethod,該方法將綁定到Person 類上榛斯,而非類的實(shí)例肠仪。類方法的第一個(gè)參數(shù)將傳入類本身,通常將參數(shù)名命名為cls异旧,上面的cls.count實(shí)際上相當(dāng)于Person.count

因?yàn)槭窃陬惿险{(diào)用荤崇,而非實(shí)例上調(diào)用,因此類方法無法獲得任何實(shí)例變量倚喂,只能獲得類的引用瓣戚。

例子:
如果將類屬性 count改為私有屬性__count,則外部無法讀取__score子库,但可以通過一個(gè)類方法獲取,請(qǐng)編寫類方法獲得__count值宴倍。

注意類方法需要添加 @classmethod

參考代碼:
    class Person(object):
        __count = 0
        @classmethod
        def how_many(cls):
            return cls.__count
        def __init__(self, name):
            self.name = name
            Person.__count = Person.__count + 1

    print Person.how_many()
    p1 = Person('Bob')
    print Person.how_many()
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鸵贬,一起剝皮案震驚了整個(gè)濱河市脖捻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌郭变,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件周伦,死亡現(xiàn)場(chǎng)離奇詭異未荒,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)寨腔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門迫卢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來乾蛤,“玉大人眨层,你說我怎么就攤上這事上荡±壹瘢” “怎么了航揉?”我有些...
    開封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我斯议,道長(zhǎng)哼御,這世上最難降的妖魔是什么看靠? 我笑而不...
    開封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮谤祖,結(jié)果婚禮上粥喜,老公的妹妹穿的比我還像新娘橘券。我一直安慰自己缩挑,他們只是感情好供置,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開白布紧阔。 她就那樣靜靜地躺著擅耽,像睡著了一般乖仇。 火紅的嫁衣襯著肌膚如雪乃沙。 梳的紋絲不亂的頭發(fā)上警儒,一...
    開封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音记劝,去河邊找鬼隆夯。 笑死蹄衷,一個(gè)胖子當(dāng)著我的面吹牛愧口,可吹牛的內(nèi)容都是我干的耍属。 我是一名探鬼主播示启,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼夫嗓,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼舍咖!你這毒婦竟也來了排霉?” 一聲冷哼從身側(cè)響起攻柠,我...
    開封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤轻抱,失蹤者是張志新(化名)和其女友劉穎祈搜,沒想到半個(gè)月后容燕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蘸秘,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了阻课。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片限煞。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡奋献,死狀恐怖秽荞,靈堂內(nèi)的尸體忽然破棺而出扬跋,到底是詐尸還是另有隱情钦听,我是刑警寧澤朴上,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站衣撬,受9級(jí)特大地震影響具练,放射性物質(zhì)發(fā)生泄漏扛点。R本人自食惡果不足惜陵究,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望牲距。 院中可真熱鬧咖摹,春花似錦萤晴、人聲如沸店读。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)趴久。三九已至彼棍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間畦幢,已是汗流浹背宇葱。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工原杂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留穿肄,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像赖欣,于是被迫代替她去往敵國(guó)和親顶吮。 傳聞我的和親對(duì)象是個(gè)殘疾皇子悴了,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355