python 類函數,實例函數,靜態函數


一、實現方法

class Function(object):
    # 在類定義中定義變量
    cls_variable = "class varibale"

    def __init__(self):
        # 在構造函數中創建變量
        self.__instance_variable = "instance variable"

    def instance_method(self):
        print(self.cls_variable)
        print(self.__instance_variable)
        print("this is a instance method")

    @staticmethod
    def static_method():
        print(Function.cls_variable)
        # print(Function.__instance_variable)    此處會報錯,無法訪問實例變量
        print("this is a static method")

    @classmethod
    def class_method(cls):
        print(cls.cls_variable)
        # print(cls.__instance_variable)   此處會報錯,無法訪問實例變量
        print("this is a class method")

    @classmethod
    def set_class_variable(cls):
        cls.cls_variable = 'new class variable'

    def set_instace_varibale(self):
        self.__instance_variable = 'new instance varibale'

#  類實例可以調用類方法和靜態方法
function1 = Function()
function1.set_class_variable()
function1.class_method()
function1.instance_method()
function1.static_method()

function2 = Function()
function2.set_instace_varibale()
function2.class_method()
function2.instance_method()
function2.static_method()


1、從代碼定義中,可以看到只是在默認傳入參數的不同。

Function.class_method()
Function.static_method()
# 可以調用實例函數,只不過需要傳入實例變量
Function.instance_method(function1)

2、從代碼訪問中,通過實例訪問這三種方法是一樣的。但是同時類訪問時,不一樣,實例函數需要傳入實例。

3、函數訪問變量中,有很大不同。

@classmethod
    def class_method(cls):
        print(cls.cls_variable)
        # print(cls.__instance_variable)   此處會報錯,無法訪問實例變量

在init函數定義的是實例變量,因為變量前綴添加了self。在類開始時定義的類變量,不需要添加前綴。

在變量訪問中,發現類函數和靜態函數是無法直接訪問實例變量的,因為在后續調用中,不知道是那個實例的。但是實例函數是可以訪問類變量的。

4、修改變量的范圍

new class variable
this is a class method
new class variable
instance variable
this is a instance method
new class variable
this is a static method

上圖是function1中輸出的結果。

new class variable
this is a class method
new class variable
new instance varibale
this is a instance method
new class variable
this is a static method
new class variable

這是function2的結果,則class variable都變化了。

如果通過類方法修改變量,則所有實例中的類變量都會修改,這個類似靜態變量了

如果通過實例修改變量,只是修改對應的實例變量。

二、三者選擇原則

通過第一節的分析,我們得知三者的不同,在訪問權限和方式上,類方法和靜態方法有很多相同之處。與實例方法的區別就是看看這個方法是不是實例獨有的方法,或者需要訪問實例變量的。另一個不同就是在繼承上了。

1、類方法和靜態方法

# -*- coding: utf-8 -*-
"""
@Time   : 2017/12/29 9:50
@Author:dongbl
@Description:
"""


class Function(object):
    X = 1
    Y = 2

    @staticmethod
    def averag(*mixes):
        return sum(mixes) / len(mixes)

    @staticmethod
    def static_method():
        # 通過function調用,如果類名修改,此處需要修改不太方便
        return Function.averag(Function.X, Function.Y)

    @classmethod
    def class_method(cls):
        return cls.averag(cls.X, cls.Y)

class Subclass(Function):
    X =3
    Y = 5

    @staticmethod
    def averag(*mixes):
        return sum(mixes) / 3

func = Subclass()
print(func.static_method())
print(func.class_method())

1、調用方式不同,另一方面就是如果類名修改,函數也修改

2、繼承。這是兩者最大的不同

1.5
2.6666666666666665

上面是兩者的輸出。

子類的實例繼承了父類的static_method靜態方法,調用該方法,還是調用的父類的方法和類屬性。
子類的實例繼承了父類的class_method類方法,調用該方法,調用的是子類的方法和子類的類屬性。

這就是最大的不同,靜態方法在類沒有初始化,已經加載了,后續繼承和她就沒有關系了。同時靜態方法關鍵明確指明了調用了Function的方法了,所以就無法修改了。這是本質。

三、類方法和實例方法

類中最常用的方法是實例方法, 即通過通過實例作為第一個參數的方法。

如果現在我們想寫一些僅僅與類交互而不是和實例交互的方法會怎么樣呢?在Python2.2以后可以使用@classmethod裝飾器來創建類方法.

比如我們創建一個類:

class DateTest():
    def __init__(self,year,month,day):
        self.year = year
        self.day = day
        self.month = month

    def print_date(self):
        print("{}:{}:{}".format(self.year,self.month,self.day))

如果用戶輸入的是“2017-12-02”這樣的字符,我們在調用類之前就需要調整一下。

這個設計角度可以理解每個實例都可以調用這個轉化函數。

# -*- coding: utf-8 -*-
"""
@Time   : 2017/12/29 9:50
@Author:dongbl
@Description:
"""
class DateTest():
    def __init__(self,year,month,day):
        self.year = year
        self.day = day
        self.month = month

    def print_date(self):
        print("{}:{}:{}".format(self.year,self.month,self.day))

    @classmethod
    def get_date(cls,string_date):
        year,month,day = map(int,string_date.split('-'))
        return cls(year,month,day)

t = DateTest(2017,9,10)
r = DateTest.get_date("2017-12-09")
r.print_date()
t.print_date()

classmethod主要用途是作為構造函數。
Python只有一個構造函數__new__,如果想要多種構造函數就很不方便。只能在new里面寫一堆if isinstance 。
有classmethod之后就可以用classmethod來寫不同的構造函數,比如:
dict.fromkeys
fractions.Fraction.from_decimal
inspect.Signature.from_function
python里面大部分classmethod最后都是 return cls(XXX), return XXX.__new__ ()之類的

staticmethod主要用途是限定namespace,也就是說這個函數雖然是個普通的function,但是它只有這個class會用到,不適合作為module level的function。這時候就把它作為staticmethod。
如果不考慮namespace的問題的話直接在module里面def function就行了。

四、參考文獻


1、python類的靜態方法和類方法區別

2、知乎經典解答


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM