自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

@classmethod與@staticmethod的區(qū)別

開發(fā) 開發(fā)工具
Python面向?qū)ο缶幊讨?,類中定義的方法可以是 @classmethod 裝飾的類方法,也可以是 @staticmethod 裝飾的靜態(tài)方法,用的最多的還是不帶裝飾器的實例方法,如果把這幾個方法放一塊,對初學(xué)者來說無疑是一頭霧水,那我們該如何正確地使用它們呢?

[[198149]]

Python面向?qū)ο缶幊讨?,類中定義的方法可以是 @classmethod 裝飾的類方法,也可以是 @staticmethod 裝飾的靜態(tài)方法,用的最多的還是不帶裝飾器的實例方法,如果把這幾個方法放一塊,對初學(xué)者來說無疑是一頭霧水,那我們該如何正確地使用它們呢?

先來看一個簡單示例:

  1. class A(object): 
  2.     def m1(self, n): 
  3.         print("self:", self) 
  4.  
  5.     @classmethod 
  6.     def m2(cls, n): 
  7.         print("cls:", cls) 
  8.  
  9.     @staticmethod 
  10.     def m3(n): 
  11.         pass 
  12.  
  13. a = A() 
  14. a.m1(1) # self: <__main__.A object at 0x000001E596E41A90> 
  15. A.m2(1) # cls: <class '__main__.A'> 
  16. A.m3(1) 

我在類中一共定義了3個方法,m1 是實例方法,***個參數(shù)必須是 self(約定俗成的)。m2 是類方法,***個參數(shù)必須是cls(同樣是約定俗成),m3 是靜態(tài)方法,參數(shù)根據(jù)業(yè)務(wù)需求定,可有可無。當(dāng)程序運行時,大概發(fā)生了這么幾件事(結(jié)合下面的圖來看)。

  • ***步:代碼從***行開始執(zhí)行 class 命令,此時會創(chuàng)建一個類 A 對象(沒錯,類也是對象,一切皆對象嘛)同時初始化類里面的屬性和方法,記住,此刻實例對象還沒創(chuàng)建出來。
  • 第二、三步:接著執(zhí)行 a=A(),系統(tǒng)自動調(diào)用類的構(gòu)造器,構(gòu)造出實例對象 a
  • 第四步:接著調(diào)用 a.m1(1) ,m1 是實例方法,內(nèi)部會自動把實例對象傳遞給 self 參數(shù)進行綁定,也就是說, self 和 a 指向的都是同一個實例對象。
  • 第五步:調(diào)用A.m2(1)時,python內(nèi)部隱式地把類對象傳遞給 cls 參數(shù),cls 和 A 都指向類對象。

嚴格意義上來說,左邊的都是變量名,是對象的引用,右邊才是真正的對像,為了描述方便,我直接把 a 稱為對象,你應(yīng)該明白我說對象其實是它所引用右邊的那個真正的對象。

再來看看每個方法各有什么特性。

實例方法

  1. print(A.m1) 
  2. # A.m1在py2中顯示為<unbound method A.m1> 
  3. <function A.m1 at 0x000002BF7FF9A488> 
  4.  
  5. print(a.m1) 
  6. <bound method A.m1 of <__main__.A object at 0x000002BF7FFA2BE0>> 

A.m1是一個還沒有綁定實例對象的方法,對于未綁定方法,調(diào)用 A.m1 時必須顯示地傳入一個實例對象進去,而 a.m1是已經(jīng)綁定了實例的方法,python隱式地把對象傳遞給了self參數(shù),所以不再手動傳遞參數(shù),這是調(diào)用實例方法的過程。

  1. A.m1(a, 1) 
  2. # 等價   
  3. a.m1(1) 

如果未綁定的方法 A.m1 不傳實例對象給 self 時,就會報參數(shù)缺失錯誤,在 py3 與 py2 中,兩者報的錯誤不一致,python2 要求***個參數(shù)self是實例對象,而python3中可以是任意對象。

  1. A.m1(1) 
  2. TypeError: m1() missing 1 required positional argument: 'n' 

類方法

  1. print(A.m2) 
  2. <bound method A.m2 of <class '__main__.A'>> 
  3.  
  4. print(a.m2) 
  5. <bound method A.m2 of <class '__main__.A'>> 

m2是類方法,不管是 A.m2 還是 a.m2,都是已經(jīng)自動綁定了類對象A的方法,對于后者,因為python可以通過實例對象a找到它所屬的類是A,找到A之后自動綁定到 cls。

  1. A.m2(1)  
  2. # 等價 
  3. a.m2(1) 

這使得我們可以在實例方法中通過使用 self.m2()這種方式來調(diào)用類方法和靜態(tài)方法。

  1. def m1(self, n): 
  2.     print("self:", self) 
  3.     self.m2(n) 

靜態(tài)方法

  1. print(A.m3) 
  2. <function A.m3 at 0x000002BF7FF9A840> 
  3.  
  4. print(a.m3) 
  5. <function A.m3 at 0x000002BF7FF9A840> 

m3是類里面的一個靜態(tài)方法,跟普通函數(shù)沒什么區(qū)別,與類和實例都沒有所謂的綁定關(guān)系,它只不過是碰巧存在類中的一個函數(shù)而已。不論是通過類還是實例都可以引用該方法。

  1. A.m3(1)  
  2. # 等價 
  3. a.m3(1) 

以上就是幾個方法的基本介紹?,F(xiàn)在把幾個基本的概念理清楚了,那么現(xiàn)在來說說幾個方法之間的使用場景以及他們之間的優(yōu)缺點。

應(yīng)用場景

靜態(tài)方法的使用場景:

如果在方法中不需要訪問任何實例方法和屬性,純粹地通過傳入?yún)?shù)并返回數(shù)據(jù)的功能性方法,那么它就適合用靜態(tài)方法來定義,它節(jié)省了實例化對象的開銷成本,往往這種方法放在類外面的模塊層作為一個函數(shù)存在也是沒問題的,而放在類中,僅為這個類服務(wù)。

例如下面是微信公眾號開發(fā)中驗證微信簽名的一個例子,它沒有引用任何類或者實例相關(guān)的屬性和方法。

  1. from hashlib import sha1 
  2. import tornado.web 
  3.  
  4. class SignatureHandler(tornado.web.RequestHandler): 
  5.     def get(self): 
  6.         """ 
  7.          根據(jù)簽名判斷請求是否來自微信 
  8.         """ 
  9.         if self._check_sign(TOKEN, timestamp, nonce, signature): 
  10.             self.write(echostr) 
  11.         else: 
  12.             self.write("你不是微信發(fā)過來的請求") 
  13.  
  14.     @staticmethod 
  15.     def _check_sign(token, timestamp, nonce, signature): 
  16.         sign = [token, timestamp, nonce] 
  17.         sign.sort() 
  18.         sign = "".join(sign) 
  19.         sign = sha1(sign).hexdigest() 
  20.         return sign == signature 

類方法的使用場景有:

作為工廠方法創(chuàng)建實例對象,例如內(nèi)置模塊 datetime.date 類中就有大量使用類方法作為工廠方法,以此來創(chuàng)建date對象。

  1. class date: 
  2.  
  3.     def __new__(cls, year, month=Noneday=None): 
  4.         self = object.__new__(cls) 
  5.         self._year = year 
  6.         self._month = month 
  7.         self._day = day 
  8.         return self 
  9.  
  10.     @classmethod 
  11.     def fromtimestamp(cls, t): 
  12.         y, m, d, * = _time.localtime(t) 
  13.         return cls(y, m, d) 
  14.  
  15.     @classmethod 
  16.     def today(cls): 
  17.         t = _time.time() 
  18.         return cls.fromtimestamp(t) 

如果希望在方法裡面調(diào)用靜態(tài)類,那么把方法定義成類方法是合適的,因為要是定義成靜態(tài)方法,那么你就要顯示地引用類A,這對繼承來說可不是一件好事情。

  1. class A: 
  2.  
  3.     @staticmethod 
  4.     def m1() 
  5.         pass 
  6.  
  7.     @staticmethod 
  8.     def m2(): 
  9.         A.m1() # bad 
  10.  
  11.     @classmethod 
  12.     def m3(cls): 
  13.         cls.m1() # good 

其實也不算是什么深入理解吧,最多算是明白怎么用,真要深入理解恐怕還要另寫一篇文章,有興趣的可以去了解一下Python的描述符。

【本文是51CTO專欄作者“劉志軍”的原創(chuàng)文章,作者微信公眾號:Python之禪(VTtalk)】

戳這里,看該作者更多好文

責(zé)任編輯:趙寧寧 來源: 51CTO專欄
相關(guān)推薦

2020-11-17 09:10:44

裝飾器

2021-12-27 07:10:26

ClassmethodStaticmetho函數(shù)

2022-09-20 07:01:50

對象初始化代碼

2009-07-06 17:08:53

JDBC與ODBC的區(qū)

2009-02-16 09:25:43

EJBJavaBeanWebSphere

2013-06-14 10:45:15

NFVSDNOpenFlow

2009-08-21 09:28:23

this與$(this

2009-06-15 14:16:17

JBoss與Tomca

2024-03-07 13:30:44

Java對象true

2017-10-26 14:59:47

MybatisHibernate數(shù)據(jù)庫

2013-01-08 15:11:19

OpenStackKVM

2009-09-22 13:12:25

Hibernateibatis

2011-03-31 10:41:49

BIONIOIO

2009-03-02 19:49:38

Mesh網(wǎng)絡(luò)Wi-FiWLAN

2013-03-21 15:27:09

LinuxUnix

2013-01-22 09:44:57

OpenStackKVM

2014-08-13 10:47:18

分布式集群

2009-06-12 09:52:49

StringStringBuffeJava

2011-06-03 18:06:33

SEO

2011-05-24 16:46:48

mallocfreenew
點贊
收藏

51CTO技術(shù)棧公眾號