新聞中心
Python面向?qū)ο缶幊讨校愔卸x的方法可以是 @classmethod 裝飾的類方法,也可以是 @staticmethod 裝飾的靜態(tài)方法,用的最多的還是不帶裝飾器的實(shí)例方法,如果把這幾個(gè)方法放一塊,對(duì)初學(xué)者來說無疑是一頭霧水,那我們?cè)撊绾握_地使用它們呢?

公司主營(yíng)業(yè)務(wù):成都做網(wǎng)站、成都網(wǎng)站設(shè)計(jì)、成都外貿(mào)網(wǎng)站建設(shè)、移動(dòng)網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。成都創(chuàng)新互聯(lián)公司是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來驚喜。成都創(chuàng)新互聯(lián)公司推出濱湖免費(fèi)做網(wǎng)站回饋大家。
先來看一個(gè)簡(jiǎn)單示例:
- class A(object):
- def m1(self, n):
- print("self:", self)
- @classmethod
- def m2(cls, n):
- print("cls:", cls)
- @staticmethod
- def m3(n):
- pass
- a = A()
- a.m1(1) # self: <__main__.A object at 0x000001E596E41A90>
- A.m2(1) # cls:
- A.m3(1)
我在類中一共定義了3個(gè)方法,m1 是實(shí)例方法,***個(gè)參數(shù)必須是 self(約定俗成的)。m2 是類方法,***個(gè)參數(shù)必須是cls(同樣是約定俗成),m3 是靜態(tài)方法,參數(shù)根據(jù)業(yè)務(wù)需求定,可有可無。當(dāng)程序運(yùn)行時(shí),大概發(fā)生了這么幾件事(結(jié)合下面的圖來看)。
- ***步:代碼從***行開始執(zhí)行 class 命令,此時(shí)會(huì)創(chuàng)建一個(gè)類 A 對(duì)象(沒錯(cuò),類也是對(duì)象,一切皆對(duì)象嘛)同時(shí)初始化類里面的屬性和方法,記住,此刻實(shí)例對(duì)象還沒創(chuàng)建出來。
- 第二、三步:接著執(zhí)行 a=A(),系統(tǒng)自動(dòng)調(diào)用類的構(gòu)造器,構(gòu)造出實(shí)例對(duì)象 a
- 第四步:接著調(diào)用 a.m1(1) ,m1 是實(shí)例方法,內(nèi)部會(huì)自動(dòng)把實(shí)例對(duì)象傳遞給 self 參數(shù)進(jìn)行綁定,也就是說, self 和 a 指向的都是同一個(gè)實(shí)例對(duì)象。
- 第五步:調(diào)用A.m2(1)時(shí),python內(nèi)部隱式地把類對(duì)象傳遞給 cls 參數(shù),cls 和 A 都指向類對(duì)象。
嚴(yán)格意義上來說,左邊的都是變量名,是對(duì)象的引用,右邊才是真正的對(duì)像,為了描述方便,我直接把 a 稱為對(duì)象,你應(yīng)該明白我說對(duì)象其實(shí)是它所引用右邊的那個(gè)真正的對(duì)象。
再來看看每個(gè)方法各有什么特性。
實(shí)例方法
- print(A.m1)
- # A.m1在py2中顯示為
- print(a.m1)
>
A.m1是一個(gè)還沒有綁定實(shí)例對(duì)象的方法,對(duì)于未綁定方法,調(diào)用 A.m1 時(shí)必須顯示地傳入一個(gè)實(shí)例對(duì)象進(jìn)去,而 a.m1是已經(jīng)綁定了實(shí)例的方法,python隱式地把對(duì)象傳遞給了self參數(shù),所以不再手動(dòng)傳遞參數(shù),這是調(diào)用實(shí)例方法的過程。
- A.m1(a, 1)
- # 等價(jià)
- a.m1(1)
如果未綁定的方法 A.m1 不傳實(shí)例對(duì)象給 self 時(shí),就會(huì)報(bào)參數(shù)缺失錯(cuò)誤,在 py3 與 py2 中,兩者報(bào)的錯(cuò)誤不一致,python2 要求***個(gè)參數(shù)self是實(shí)例對(duì)象,而python3中可以是任意對(duì)象。
- A.m1(1)
- TypeError: m1() missing 1 required positional argument: 'n'
類方法
- print(A.m2)
> - print(a.m2)
>
m2是類方法,不管是 A.m2 還是 a.m2,都是已經(jīng)自動(dòng)綁定了類對(duì)象A的方法,對(duì)于后者,因?yàn)閜ython可以通過實(shí)例對(duì)象a找到它所屬的類是A,找到A之后自動(dòng)綁定到 cls。
- A.m2(1)
- # 等價(jià)
- a.m2(1)
這使得我們可以在實(shí)例方法中通過使用 self.m2()這種方式來調(diào)用類方法和靜態(tài)方法。
- def m1(self, n):
- print("self:", self)
- self.m2(n)
靜態(tài)方法
- print(A.m3)
- print(a.m3)
m3是類里面的一個(gè)靜態(tài)方法,跟普通函數(shù)沒什么區(qū)別,與類和實(shí)例都沒有所謂的綁定關(guān)系,它只不過是碰巧存在類中的一個(gè)函數(shù)而已。不論是通過類還是實(shí)例都可以引用該方法。
- A.m3(1)
- # 等價(jià)
- a.m3(1)
以上就是幾個(gè)方法的基本介紹?,F(xiàn)在把幾個(gè)基本的概念理清楚了,那么現(xiàn)在來說說幾個(gè)方法之間的使用場(chǎng)景以及他們之間的優(yōu)缺點(diǎn)。
應(yīng)用場(chǎng)景
靜態(tài)方法的使用場(chǎng)景:
如果在方法中不需要訪問任何實(shí)例方法和屬性,純粹地通過傳入?yún)?shù)并返回?cái)?shù)據(jù)的功能性方法,那么它就適合用靜態(tài)方法來定義,它節(jié)省了實(shí)例化對(duì)象的開銷成本,往往這種方法放在類外面的模塊層作為一個(gè)函數(shù)存在也是沒問題的,而放在類中,僅為這個(gè)類服務(wù)。
例如下面是微信公眾號(hào)開發(fā)中驗(yàn)證微信簽名的一個(gè)例子,它沒有引用任何類或者實(shí)例相關(guān)的屬性和方法。
- from hashlib import sha1
- import tornado.web
- class SignatureHandler(tornado.web.RequestHandler):
- def get(self):
- """
- 根據(jù)簽名判斷請(qǐng)求是否來自微信
- """
- if self._check_sign(TOKEN, timestamp, nonce, signature):
- self.write(echostr)
- else:
- self.write("你不是微信發(fā)過來的請(qǐng)求")
- @staticmethod
- def _check_sign(token, timestamp, nonce, signature):
- sign = [token, timestamp, nonce]
- sign.sort()
- sign = "".join(sign)
- sign = sha1(sign).hexdigest()
- return sign == signature
類方法的使用場(chǎng)景有:
作為工廠方法創(chuàng)建實(shí)例對(duì)象,例如內(nèi)置模塊 datetime.date 類中就有大量使用類方法作為工廠方法,以此來創(chuàng)建date對(duì)象。
- class date:
- def __new__(cls, year, month=None, day=None):
- self = object.__new__(cls)
- self._year = year
- self._month = month
- self._day = day
- return self
- @classmethod
- def fromtimestamp(cls, t):
- y, m, d, * = _time.localtime(t)
- return cls(y, m, d)
- @classmethod
- def today(cls):
- t = _time.time()
- return cls.fromtimestamp(t)
如果希望在方法裡面調(diào)用靜態(tài)類,那么把方法定義成類方法是合適的,因?yàn)橐嵌x成靜態(tài)方法,那么你就要顯示地引用類A,這對(duì)繼承來說可不是一件好事情。
- class A:
- @staticmethod
- def m1()
- pass
- @staticmethod
- def m2():
- A.m1() # bad
- @classmethod
- def m3(cls):
- cls.m1() # good
其實(shí)也不算是什么深入理解吧,最多算是明白怎么用,真要深入理解恐怕還要另寫一篇文章,有興趣的可以去了解一下Python的描述符。
【本文是專欄作者“劉志軍”的原創(chuàng)文章,作者微信公眾號(hào):Python之禪(VTtalk)】
戳這里,看該作者更多好文
標(biāo)題名稱:@classmethod與@staticmethod的區(qū)別
文章地址:http://www.dlmjj.cn/article/dhigshj.html


咨詢
建站咨詢
