咱們在類中定義的方法都是對象方法,也就是說這些方法都是發送給對象的消息。實際上,咱們寫在類中的方法並不須要都是對象方法,例如咱們定義一個「三角形」類,經過傳入三條邊長來構造三角形,並提供計算周長和麪積的方法,可是傳入的三條邊長未必能構造出三角形對象,所以咱們能夠先寫一個方法來驗證三條邊長是否能夠構成三角形,這個方法很顯然就不是對象方法,由於在調用這個方法時三角形對象還沒有建立出來(由於都不知道三條邊能不能構成三角形),因此這個方法是屬於三角形類而並不屬於三角形對象的。咱們可使用靜態方法來解決這類問題,代碼以下所示。java
from math import sqrt class Triangle(object): def __init__(self, a, b, c): self._a = a self._b = b self._c = c @staticmethod def is_valid(a, b, c): return a + b > c and b + c > a and a + c > b def perimeter(self): return self._a + self._b + self._c def area(self): half = self.perimeter() / 2 return sqrt(half * (half - self._a) * (half - self._b) * (half - self._c)) def main(): a, b, c = 3, 4, 5 # 靜態方法和類方法都是經過給類發消息來調用的 if Triangle.is_valid(a, b, c): t = Triangle(a, b, c) print(t.perimeter()) # 也能夠經過給類發消息來調用對象方法可是要傳入接收消息的對象做爲參數 # print(Triangle.perimeter(t)) print(t.area()) # print(Triangle.area(t)) else: print('沒法構成三角形.') if __name__ == '__main__': main()
和靜態方法比較相似,Python還能夠在類中定義類方法,類方法的第一個參數約定名爲cls,它表明的是當前類相關的信息的對象(類自己也是一個對象,有的地方也稱之爲類的元數據對象),經過這個參數咱們能夠獲取和類相關的信息而且能夠建立出類的對象,代碼以下所示。python
from time import time, localtime, sleep class Clock(object): """數字時鐘""" def __init__(self, hour=0, minute=0, second=0): self._hour = hour self._minute = minute self._second = second @classmethod def now(cls): ctime = localtime(time()) return cls(ctime.tm_hour, ctime.tm_min, ctime.tm_sec) def run(self): """走字""" self._second += 1 if self._second == 60: self._second = 0 self._minute += 1 if self._minute == 60: self._minute = 0 self._hour += 1 if self._hour == 24: self._hour = 0 def show(self): """顯示時間""" return '%02d:%02d:%02d' % \ (self._hour, self._minute, self._second) def main(): # 經過類方法建立對象並獲取系統時間 clock = Clock.now() while True: print(clock.show()) sleep(1) clock.run() if __name__ == '__main__': main()
因爲python類中只能有一個初始化方法,不能按照不一樣的狀況初始化類。
參考django https://docs.djangoproject.com/en/1.9/ref/models/instances/ 請看下面的代碼。django
# coding:utf-8 class Book(object): def __init__(self, title): self.title = title @classmethod def create(cls, title): book = cls(title=title) return book book1 = Book("python") book2 = Book.create("python and django") print(book1.title) print(book2.title)
特別說明,靜態方法也能夠實現上面功能,當靜態方法每次都要寫上類的名字,不方便。函數
下面的代碼,靜態方法調用另外一個靜態方法,若是改用類方法調用靜態方法,可讓cls代替類,
讓代碼看起來精簡一些。也防止類名修改了,不用在類定義中修改原來的類名。code
# coding:utf-8 class Foo(object): X = 1 Y = 2 @staticmethod def averag(*mixes): return sum(mixes) / len(mixes) @staticmethod def static_method(): return Foo.averag(Foo.X, Foo.Y) @classmethod def class_method(cls): return cls.averag(cls.X, cls.Y) foo = Foo() print(foo.static_method()) print(foo.class_method())
從下面代碼能夠看出,若是子類繼承父類的方法,子類覆蓋了父類的靜態方法,
子類的實例繼承了父類的static_method靜態方法,調用該方法,仍是調用的父類的方法和類屬性。
子類的實例繼承了父類的class_method類方法,調用該方法,調用的是子類的方法和子類的類屬性。對象
# coding:utf-8 class Foo(object): X = 1 Y = 2 @staticmethod def averag(*mixes): return sum(mixes) / len(mixes) @staticmethod def static_method(): return Foo.averag(Foo.X, Foo.Y) @classmethod def class_method(cls): return cls.averag(cls.X, cls.Y) class Son(Foo): X = 3 Y = 5 @staticmethod def averag(*mixes): return sum(mixes) / 3 p = Son() print(p.static_method()) print(p.class_method()) # 1.5 # 2.6666666666666665