深入了解Python 方法之類方法 靜態方法

2022-09-26 12:18:10 字數 3893 閱讀 2802

寫在之前

昨天的文章 詳解類方法之繫結方法與非繫結方法 中寫了方法中的繫結方法和非繫結方法,今天我們繼續來學習剩下的「類方法」和「靜態方法」。

類方法 & 靜態方法

在開始之前,先讓我們來看下面一段**:

class sample:

language = "c++"

def __init__(self):

self.language = "python"

def get_class_attr(cls):

return cls.language

if __name__ == "__main__":

print("sample.language:",sample.language)

r = get_class_attr(sample)

print("get class attribute:",r)

f = sample()

print("instance attribute:",f.language)

上述**在類 sample 中,定義了乙個屬性 language = 「c++」,這個是「類屬性」;在初始化方法中,又定義了 self.language = 「python」,這個是「例項屬性」。

知道了這個,我們然後來分析一下函式 get_class_attr(cls),在這個函式中引數用的是 cls,從函式體來看,要求它引用的物件應該具有屬性 language,這說明,不是隨隨便便哪個物件都可以。很巧的是在前面定義的類 samplzolksosvlee 中就有 language 這個屬性,於是在呼叫這個函式的時候,就直接將該類物件作為方法 get_class_attr() 的引數。

sample.language 是要得到類屬性的值,get_class_attr(sample) 所返回的就是類 sample 的屬性 sample.language 的值,所以對於上述例子來說,前面兩個 p程式設計客棧rint() 函式列印的結果應該是一樣的。

f = sample() 則是建立了乙個例項,然後通過 f.language 訪問例項屬性。所以對於上述的**的執行結果如下所示:

sample.language:c++

get class attribute:c++

instance attribute:python

不知道經過我上述的解釋你是否明白了,如果沒明白,建議你再仔細對比一下上述的執行結果和分析的過程。

在上述的例子中,比較特殊的函式應該是 get_class_attr(cls),它是寫在類的外面的,然而這個函式又只能呼叫前面寫zolksosvle的那個類物件,因為不是所有物件都有那個特別的 language 屬性,這種函式寫在外面不利於後期的維護,我們應該避免這種情況的發生,而避免的方法就是把函式和類寫在一起,所以就有了下面這種寫法:

class sample:

language = "c++"

def __init__(self):

self.language = "python"

@classmethod

def get_class_attr(cls):

return cls.language

if __name__ == "__main__":

print("sample.language:",sample.language)

r = sample.get_class_attr()

print("get class attribute:",r)

f = sample()

print("instance attribute:",f.language)

print("instance get_class_str:",f.get_class_attr())

在上面這個修改的**中,出現了 @classmethod,這是乙個裝飾器,我們在函式的那部分講到過。這裡需要我們注意的是,@classmethod 所裝飾的方法的引數中,第乙個引數不是 self,這個和我們常規認識中的類的方法有所區別。這裡使用了引數 cls,這是習慣的寫法,當然用其它的也可以。讓我們來看一下執行的結果:

sample.language:c++

get class attribute:c++

instance attribute:python

instance get_class_str:c++

通過上面的執行結果我們可以看到,不管是通過類還是例項來執行 get_class_attr() 得到的結果都是類屬性的值,這說明裝飾器 @classmethod 所裝飾的方法,它的引數 cls 引用的物件是類物件 sample。

至此,「類方法」 的定義就出來了:類方法,就是在類裡面定義的方法。該方法由裝飾器 @classmethod 裝飾,其第乙個引數 cls 引用的是這個類物件,即將類本身作為作為引用物件傳到這個方法裡。

知道了類方法以後,我們可以用同樣的思路理解另乙個方法 「靜態方法」,我們還是先來看一段**:

import random

def judge(n):

num = random.randint(1,100)

return num - n > 0

class sample:

def __init__(self,name):

self.name = name

def get_name(self,age):

if judge(age):

return self.name

else:

return "the name is stupid"

if __name__ == "__main__":

s = sample('rocky')

name = s.get_name(23)

print(name)

先看一下上面的**,類 sample 裡面使用了外面的函式 judge(n),這種類和函式的關係也是因為相互關聯,所以後期的程式維護可能會出問題,於是為了便於維護,我們同樣對程式進行了修改:

import random

class sample:

def __init__(self,name):

self.name = name

def get_name(self,age):

if self.judge(age):

return self.name

else:

return "the name is stupid"

@szolksosvletaticmethod

def judge(n):

num = random.randint(1,100)

return num - n > 0

if __name__ == "__main__":

s = sample('ro程式設計客棧cky')

name = s.get_name(23)

print(name)

同樣是經過修改優化,將原來在類外面的函式放到了類裡面。但是這不是簡單的移動,還要在函式的前面加上 @staticmethod 裝飾器,並且要注意的是,雖然這個函式在類的裡面,但是跟別的方法是不一樣的,它的第乙個引數也不是 self,當我們要使用它的時候,可以通過例項呼叫,比如 self.judge(n),也可以通過類呼叫這個方法,比如 sample.select(n)。

從上面的程式可以看出,儘管 judge(n) 位於類裡面,但它確實乙個獨立的方法,與類本身沒有關係,僅僅是為了免除前面所說的後期維護上的麻煩。但是它也有存在的道理,上面的例子就是乙個典型的說明。

所以「靜態方法」的定義也就出來了:在類的作用域裡面,前面必須要加上乙個 @staticmethod 裝飾器,我們將這種方法命名為靜態方法。

寫在之後

方法是類的重要組成部分,本章所講的類方法和靜態方法讓我們在使用類的時候有了更加便利的工具。

「方法」的這一塊到這裡就補充完了,之後我們將繼續學習 oop 的剩下兩個特徵:「多型」和「封裝」,敬請期待。

the end。

深入了解A

一 前言 在這裡我將對a 演算法的實際應用進行一定的 並且舉乙個有關a 演算法在最短路徑搜尋的例子。值得注意的是這裡並不對a 的基本的概念作介紹,如果你還對a 演算法不清楚的話,請看姊妹篇 初識a 演算法 這裡所舉的例子是參考amit主頁中的乙個源程式,使用這個源程式時,應該遵守一定的公約。二 a ...

深入了解A

一 前言 在這裡我將對a 演算法的實際應用進行一定的 並且舉乙個有關a 演算法在最短路徑搜尋的例子。值得注意的是這裡並不對a 的基本的概念作介紹,如果你還對a 演算法不清楚的話,請看姊妹篇 初識a 演算法 這裡所舉的例子是參考amit主頁中的乙個源程式,使用這個源程式時,應該遵守一定的公約。二 a ...

深入了解Python的繼承

目錄 繼承的概念 子類 擁有 父類 的所有 方法 和 屬性 不使用繼承類 class animal def eat self print 吃 def drink self print 喝 def run self print 跑 def sleep self print 睡 class dog de...