也許一些例子會有幫助:注意foo
, class_foo
和static_foo
參數的區別:java
class A(object): a = 'a' def __init__(self): self.b = 'b' def foo(self,x): print "executing foo(%s,%s)"%(self,x) @classmethod def class_foo(cls,x): print cls.static_foo('2') cls.name = 'A1' print dir(cls) print "executing class_foo(%s,%s)"%(cls,x) @staticmethod def static_foo(x): print "executing static_foo(%s)"%x a=A()
下面是一個對象實體調用方法的經常使用方式.對象實體a
被隱藏的傳遞給了第一個參數.python
a.foo(1) # executing foo(<__main__.A object at 0xb7dbef0c>,1)
用classmethod裝飾,隱藏的傳遞給第一個參數的是對象實體的類(class A
)而不是self
.c++
a.class_foo(1) # executing class_foo(<class '__main__.A'>,1)
你也能夠用類調用class_foo
.實際上,若是你把一些方法定義成classmethod
,那麼實際上你是但願用類來調用這個方法,而不是用這個類的實例來調用這個方法.A.foo(1)
將會返回一個TypeError
錯誤, A.class_foo(1)
將會正常運行:函數
A.foo(1) #TypeError: unbound method foo() must be called with A instance as first argument (got str instance instead) # 這時可想到把示例化的a傳進去怎麼樣?結果證明可行,和a.foo(1)效果同樣,但不建議這樣使用 # 其實f1 = A.foo, a = A(), f2 = a.foo, f1是unbound method,f2是bound method # 具體可見https://my.oschina.net/u/914655/blog/1546281 A.foo(a, 1) # executing foo(<__main__.A object at 0xb7dbef0c>,1) A.class_foo(1) # executing class_foo(<class '__main__.A'>,1)
用staticmethod來裝飾,無論傳遞給第一個參數的是self
(對象實體)仍是cls
(類).它們的表現都同樣:.net
a.static_foo(1) # executing static_foo(1) A.static_foo('hi') # executing static_foo(hi)
靜態方法被用來組織類之間有邏輯關係的函數.code
foo
只是個函數,可是當你調用a.foo
的時候你獲得的不單單是一個函數,你獲得的是一個第一個參數綁定到a
的"增強版"函數. python解析器會自動把a示例綁定到foo的第一個參數參數上對象
a
綁定了foo
.下面能夠知道什麼叫"綁定"了:blog
print(a.foo) # <bound method A.foo of <__main__.A object at 0xb7d52f0c>>
若是使用a.class_foo
, 是A
綁定到了class_foo
而不是實例a
.繼承
print(a.class_foo) # <bound method type.class_foo of <class '__main__.A'>>
最後剩下靜態方法,說到底它就是一個函數. a.static_foo
只是返回一個不帶參數綁定的函數. static_foo
和a.static_foo
只須要一個參數.字符串
print(a.static_foo) # <function static_foo at 0xb7d479cc>
總結:
類實例對象
的參數。也即持有類實例對象,須要實例化的類才能調用或者直接把實例化參數傳入第一個,見上面類對象
的參數。也即持有類對象,在不需實例化的狀況下調用類的屬性等區別本質有了,具體幾個應用以下:
最直接應用就是,加了這2個裝飾器,就能夠不須要實例化,直接經過 類名.函數名()
來調用,有利於組織代碼,把屬於某個類的函數,但又不需實例化的給放進類裏去,同時有利於命名空間的整潔。
1. 構造多個構造函數
因爲python裏沒有java的重載機制(java裏同方法名不一樣參數認爲是不一樣的方法,python裏只要方法名惟一),可經過classmethod的特性構造多個構造函數
class Date(object): def __init__(self, day=0, month=0, year=0): self.day = day self.month = month self.year = year 好比Date類,咱們要實例化它,必須傳入day, month, year 加入咱們有個string_date = '11-4-2017' 必須按以下方式處理 day, month, year = map(int, string_date.split('-')) date1 = Date(day, month, year) c++ java等語言有重載的特性,但python沒有,這時咱們就能夠經過classmethod來實現 @classmethod def from_string(cls, date_as_string): day, month, year = map(int, date_as_string.split('-')) date1 = cls(day, month, year) return date1 # 如今直接經過調用from_string便可 date2 = Date.from_string('11-09-2012') # 並且有如下好處 # 1. 針對此類的日期解析函數在本類裏,方便管理,並且可重用 # 2. cls是一個持有類自己的對象,而不是類的一個實例。這很酷,由於若是咱們繼承咱們的Date類,全部的孩子也將有from_string定義。
接着上面,假如字符串格式不是'dd-mm-yyyy'格式,執行from_string就不會獲得想要的結果,這時咱們要檢驗這個值,此時staticmethod就會很合適
@staticmethod def is_date_valid(date_as_string): day, month, year = map(int, date_as_string.split('-')) return day <= 31 and month <= 12 and year <= 3999 # usage: is_date = Date.is_date_valid('11-09-2012')