Python靜態(tài)方法和類方法

方法就是一個(gè)函數(shù),它作為一個(gè)類屬性而存在,可以使用如下方式進(jìn)行聲明、訪問(wèn)一個(gè)函數(shù):

class Student(object):
      def __init__(self,sex):
          self.sex = sex
      
      def get_sex(self):
          return self.sex

print Student.get_sex
<unbound method Student.get_sex>

Python在告訴你,屬性get_sex是類Student的一個(gè)未綁定的方法。這是什么意思

print print Student.get_sex()
Traceback (most recent call last):
  File "D:/project_11/SmartCleaner_python/home_application/__init__.py", line 13, in <module>
    print Student.get_sex()
TypeError: unbound method get_sex() must be called with Student instance as first argument (got nothing instead)

這樣不能進(jìn)行調(diào)用,因?yàn)樗€沒(méi)有綁定到Student類的任何實(shí)例對(duì)象上,它需要一個(gè)實(shí)例作為第一個(gè)參數(shù)傳遞進(jìn)去(Python2必須是該類的實(shí)例,Python3中可以是任何東西),如下:

print Student.get_sex(Student('OK'))
OK

現(xiàn)在用一個(gè)實(shí)例對(duì)象作為它的第一個(gè)參數(shù)來(lái)調(diào)用,但是這種還是不最方便的,如果每次調(diào)用這個(gè)方法,不得不引用這個(gè)類,隨著代碼量的增加,如果忘記了哪個(gè)類是所需要的,會(huì)造成程序的混亂,所以長(zhǎng)期看來(lái)這種方法是行不通的。
Python綁定了所有來(lái)自類Student的方法以及該類的任何一個(gè)實(shí)例方法,也就是以為著現(xiàn)在屬性get_sex是Student的一個(gè)實(shí)例對(duì)象的綁定方法,這個(gè)方法的第一個(gè)參數(shù)就是該實(shí)例本身。

print Student('OK').get_sex
<bound method Student.get_sex of <__main__.Student object at 0x0000000003116898>
print Student('OK').get_sex()
OK

現(xiàn)在不需要提供任何參數(shù)給get_sex,因?yàn)樗呀?jīng)是綁定的,它的self參數(shù)會(huì)自動(dòng)的設(shè)置給Pizza實(shí)例。

student = Student('OK').get_sex
print student()
OK

獲取綁定的方法在哪個(gè)對(duì)象上

student = Student('OK').get_sex
print student.__self__
print student == student.__self__.get_sex
<__main__.Student object at 0x0000000003116898>
True

在Python3中,依附在類上的函數(shù)不再當(dāng)作是未綁定的方法,二十把它當(dāng)作一個(gè)簡(jiǎn)單函數(shù),如果有必要它會(huì)綁定到一個(gè)對(duì)象身上去,原則依然和Python保持一致,但是模塊更簡(jiǎn)潔:

lass Student(object):
      def __init__(self,sex):
          self.sex = sex
      
      def get_sex(self):
          return self.sex

print Student.get_sex
<__main__.Student object at 0x0000000003116898>

靜態(tài)方法

靜態(tài)方法是一類特殊的方法,有時(shí)可能需要寫一個(gè)屬于這個(gè)類的方法,但是這些代碼完全不會(huì)使用到實(shí)例對(duì)象本身,例如:

class Student(object):
    @staticmethod
    def aver_age(x, y):
        return x + y

    def year(self):
        return self.aver_age(self.month, self.day)

這個(gè)例子中,如果把a(bǔ)ver_age作為非靜態(tài)方法同樣可以運(yùn)行,但是它要提供self參數(shù),而這個(gè)參數(shù)在方法中根本不會(huì)被使用到。這里的@staticmethod裝飾器可以給我們帶來(lái)一些好處,Python不再需要為Student對(duì)象實(shí)例初始化一個(gè)綁定方法,綁定方法同樣是對(duì)象,但是創(chuàng)建需要成本,而靜態(tài)方法可以避免這些。

Student().year is Student().year
Student().aver_age is Student().aver_age
Student().aver_age is Student.aver_age
False
True
True

可讀性更好的代碼,看到@staticmethod我們就知道這個(gè)方法并不需要依賴對(duì)象本身的狀態(tài)。
可以在子類中被覆蓋,如果是把a(bǔ)ver_age作為模塊的頂層函數(shù),那么繼承自Student的子類就沒(méi)法改變Student的aver_age了如果不覆蓋year的話。

類方法

什么是類方法?類方法不是綁定到對(duì)象上,而是綁定在類上的方法。

class Student(object):
    score = 100

    @classmethod
    def get_score(cls):
        return cls.score

print Student.get_score
print Student().get_score
print Student().get_score is Student.get_score
print Student.get_score()

<bound method type.get_score of <class '__main__.Student'>>
<bound method type.get_score of <class '__main__.Student'>>
False
100

無(wú)論用哪種方式訪問(wèn)這個(gè)方法,它總是綁定到了這個(gè)類身上,它的第一個(gè)參數(shù)是這個(gè)類本身(類也是對(duì)象)
什么時(shí)候使用這種方法呢? 類方法通常在以下兩種場(chǎng)景是非常有用的:

  • 工廠方法: 它用于創(chuàng)建類的實(shí)例,例如一些預(yù)處理。如果使用@staticmethod代替,那我們不得不硬編碼Student類名在函數(shù)中,這使得任何繼承Student的類都不能使用我們這個(gè)工廠方法給它自己用。
class Student(object):
  def __init__(self, age):
    self.age= age

  @classmethod
  def year_day(cls, year):
    return cls(year.get_cheese() + fridge.get_day())
  • 調(diào)用靜態(tài)類:如果把一個(gè)靜態(tài)放啊拆分多個(gè)靜態(tài)方法,除非使用類方法,否則還是得硬編碼類名。使用這種方式聲明方法,Student類名永遠(yuǎn)都不會(huì)再被直接飲用,繼承和方法覆蓋都可以完美的工作。
class Student(object):
      def __init__(self,heigh,weigh):  
          self.heigh = heigh
          self.weigh = weigh
      @staticmethod
      def compute(heigh):
          return math.pi * (heigh ** 2)
     
      @classmethod
       def compute_value(cls,heigh,wegigh):
           return weigh * cls.compute(heugh)

      def get_value(self):
            return self.conpute_value(self.heigh, self.weigh)
  • 抽象方法
    抽象方法是定義在基類中的一種方法,它沒(méi)有提供任何實(shí)現(xiàn),類似于Java中接口(Interface)里面的方法。
    在Python中實(shí)現(xiàn)抽象方法最簡(jiǎn)單的方式:
class Student(object):
      def get_score(self):
          raise NotImplementedError

人格繼承自Student的類必須覆蓋實(shí)現(xiàn)方法get_score,否則會(huì)拋出異常。
這種抽象方法的實(shí)現(xiàn)有它的弊端,如果你寫一個(gè)類繼承Student,但是忘記實(shí)現(xiàn)get_score,異常只要在正在使用的時(shí)候才會(huì)拋出來(lái)。

>>> Student()
<__main__.Student object at 0x7fb747353d90>
>>> Student().get_score()
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File "<stdin>", line 3, in get_score
NotImplementedError

還有一種方式可以讓錯(cuò)誤更早的觸發(fā),使用Python提供的abc模塊,對(duì)象被初始化之后就可以拋出異常:

import abc

class BaseStudent(obiect):
      __metaclass__ =  abc.ADCMeta

      @abc.abstractmethod
      def get_score(self):

"""Method that should do something."""

使用abc,當(dāng)你嘗試初始化BaseStudent或者任何子類的時(shí)候立馬就會(huì)得到一個(gè)TypeError,而無(wú)需等到真正調(diào)用get_score的時(shí)候才會(huì)發(fā)現(xiàn)異常。

BaseStudent()
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class BaseStudent with abstract methods get_score
  • 混合靜態(tài)方法、類方法、抽象方法

當(dāng)開(kāi)始構(gòu)建類和繼承結(jié)構(gòu)時(shí),混個(gè)使用這些裝飾器的時(shí)候到了,所以這里列出了一些技巧,聲明一個(gè)抽象的方法,不會(huì)固定方法的原型,這就是意味著雖然雖然必須實(shí)現(xiàn)它,但是可以用任何參數(shù)列表來(lái)實(shí)現(xiàn):

import abc

class BaseStudent(obiect):
      __metaclass__ =  abc.ADCMeta

      @abc.abstractmethod
      def get_score(self):

""""Returns the score list."""

class Message(BaseStudent):
      def get_msg(self,add,with_sex=False):
          sex = Sex() if with_sex else None
          return self.get_msg + sex

這樣是允許的因?yàn)镸essage滿足BaseStudent對(duì)象所定義的接口需求。同樣也可以使用一個(gè)類方法或靜態(tài)方法進(jìn)行實(shí)現(xiàn):

import abc

class BaseStudent(object):
  __metaclass__ = abc.ABCMeta

  @abc.abstractmethod
  def get_score(self):

"""Returns the score list."""

class Obj(BasePizza):
  @staticmethod
  def get_msg():
    return None

這同樣是正確的,因?yàn)樗裱橄箢怋aseStudent設(shè)定的契約。事實(shí)上get_msg方法并不需要知道返回結(jié)果是什么,結(jié)果是實(shí)現(xiàn)細(xì)節(jié),不是契約條件。
因此,不能強(qiáng)制抽象方法的實(shí)現(xiàn)是一個(gè)常規(guī)方法、或者是類方法還是靜態(tài) 方法,也沒(méi)什么可爭(zhēng)論的。從Python3開(kāi)始(在Python2中不能如所期待的的運(yùn)行),在avstractmethod方法上面使用@staticmethod和@classmethod裝飾器為可能。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1.staticmethod 類的靜態(tài)方法,是類中使用staticmethod裝飾的方法。可通過(guò)類本身或者類實(shí)例來(lái)...
    第八共同體閱讀 925評(píng)論 0 1
  • 轉(zhuǎn)載自Python 靜態(tài)方法和類方法的區(qū)別 盡管 classmethod 和 staticmethod 非常相似,...
    lucasdada閱讀 308評(píng)論 0 0
  • Part 1. 我們都喜歡說(shuō)“隨便” 記得有次季度會(huì)議,大家從四面八方聚到總公司。 三天時(shí)間開(kāi)完了公司會(huì)議,我們經(jīng)...
    秦公子書(shū)影閱讀 610評(píng)論 3 7
  • 那是在我準(zhǔn)備做腸鏡的前一天下午,媽媽去鹵菜店買了一只鴨,說(shuō)是給晚飯加個(gè)菜。而我由于明天要做腸鏡所以只能喝無(wú)...
    山DING閱讀 360評(píng)論 0 1
  • 清晨,我與早起的小鳥(niǎo) 翅膀上還濕著露水的小鳥(niǎo) 一起出發(fā) 穿過(guò)花池,穿過(guò)草地 走進(jìn)熹微朦朧的四月森林 我走進(jìn)森林,迷...
    玉木YUMU閱讀 654評(píng)論 0 0

友情鏈接更多精彩內(nèi)容