1. 程式人生 > >python類方法與靜態方法

python類方法與靜態方法

類方法與靜態方法

類方法

首先需要明確的類方法是用裝飾器進行裝飾的,那麼裝飾器的原理就在於在進行被裝飾函式執行之前先進行裝飾函式的執行.這就非常有意思的將被裝飾函式包裝起來

可以更加形象的理解裝飾器就是在被裝飾函式執行前先進行審查,只有通過審查的引數才能被傳到被裝飾函式中,甚至是可以選擇對所有傳入的引數都選擇忽略,一個都不給被裝飾函式

class New(object):
    def __init__(self, num1, num2):
        self.num1 = num1
        self.num2 = num2
        
    @classmethod
def class_fun(cls): print(f'+++++++++{cls}') @staticmethod def static_fun(args): print(f"========={args}") New.class_fun() New.static_fun(10000)

裝飾器@classmethod實質就是裝飾器,注意到cls這個函式接收的引數cls,當然可以隨便寫,形參不管取什麼名字都可以,但是這裡不能沒有,類方法會自動的將類傳入進去,這裡必須用一個引數進行接收

誰完成的這個事情

@classmethod這個裝飾器完成的,實際上外面用類名進行呼叫的時候是沒有辦法對類進行傳引數的,而class_fun方法確又定義了一個引數cls,沒有報錯則表明這個引數已經傳進去了,外面沒有給那麼只能是裝飾器裡面自動給的,所以這個裝飾器在這裡的作用就是不管從外面怎麼傳引數,裝飾器統統接受,但是裝飾內部給class_fun的引數只有一個,就是類本身

注意到初始化函式,實際要求的是需要給類傳遞兩個引數作為物件屬性,顯然這裡在進行類方法呼叫的時候沒有給,這就說明實際上呼叫類方法的時候根本就沒有例項化

以上說明所謂的類方法,其實就是一個方法被裝飾器裝飾後篩掉所有的引數只給被裝飾函式傳遞一個類的方法,這個cls你可以寫成a b c d 任意符合命名規範的變數名,只是通常我們習慣寫cls

靜態方法

靜態方法更像是一個定義在類外面的方法,因為這個方法可以不接受任何引數,甚至連類都不接受,注意到其實這個寫在類裡面的方法實際上也是通過裝飾器進行修飾的,那麼這個裝飾器就像是一個保安大哥一樣,拒絕所有的類和物件傳入被裝飾函式.其核心在於過濾掉一切外部物件和類的傳入,當然你被裝飾函式需要的引數還是照常傳,只是不再像物件方法和類方法一樣,預設的給物件本身和類本身

靜態方法通過類名進行呼叫,但是又不接受這個類,感覺還不如定義在外面,實際上並不是這樣的,雖然方法的執行與類並沒有任何關係,但是其被封裝到類裡面,這個方法可以跟隨物件走,也可以繼承,更像是一種打包給這個類的東西,就像你買東西一樣,商家還送你一些小玩意

class New(object):
    def __init__(self, num1, num2):
        self.num1 = num1
        self.num2 = num2

    @classmethod
    def class_fun(cls):
        print(f'+++++++++{cls}')

    @staticmethod
    def static_fun(args):
        print(f"========={args}")

class Son(New):
    pass

New.class_fun()
New.static_fun(10000)
Son.static_fun('繼承的方法')

類例項化的過程

魔術方法裡面有兩個需要區分

__init__
__new__

init用來初始化物件

new用來建立物件,那麼初始化過程一定是發生在建立過程之後的

當進行物件例項化的時候,實際上會存在兩個空間,類空間和物件空間,如果是物件方法和物件屬性則存放在物件空間中,如果是類方法和類屬性則存放在類空間中

class Other(object):
    other_attr = '其他類'


class New(object):
    def __init__(self):
        if self.class_attr == '類屬性':
            print(self.class_attr)
            print('初始化前已經存在類空間')
        self.class_attr = '物件屬性'
        print(self.class_attr)
        print('=====================')
        print(self.new_attr)
        print('**********************')
        print(self.new_attr.other_attr)
        self.new_attr.other_attr = '修改屬性'
        print('--------------------------')
        print(self.new_attr.other_attr)
        print('故意寫錯')
        self.new_attr.other_attr_ = '不會報錯,這裡直接呼叫'
        print(self.new_attr.other_attr_)

    class_attr = '類屬性'
    new_attr = Other()


test = New()

以上的結果可以說明類實際在例項化的時候先載入的是類裡面類方法和類屬性,之後再例項化物件,例項化物件成功之後再進行初始化,在初始化過程中呼叫了類屬性,這個new_attr屬性實際上又是一個例項化物件,所以這個屬性實際上是一個物件,那麼在使用self.new_attr.other_attr的時候本身就已經從這個物件上去找物件屬性了,而Other這個類中沒有物件屬性,所以搜尋空間繼續上找,在類空間找到了類屬性,因此這裡的鏈式查詢就返回了’其他類’

這種類屬性是另外一個類例項化物件的這種方式在很多框架的原始碼中用的比較多

核心思想就是鏈式查詢

故意寫錯的的地方如果不是採用的賦值操作的話就會報錯,其實道理很簡單,物件.類屬性 = 值 這種寫法就好像是在類外面進行物件的物件屬性賦值