Python的方法主要有3個,即靜態方法(staticmethod),類方法(classmethod)和實例方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
def
foo(x):
print
"executing foo(%s)"
%
(x)
class
A(
object
):
def
foo(
self
,x):
print
"executing foo(%s,%s)"
%
(
self
,x)
@classmethod
def
class_foo(
cls
,x):
print
"executing class_foo(%s,%s)"
%
(
cls
,x)
@staticmethod
def
static_foo(x):
print
"executing static_foo(%s)"
%
x
a
=
A()
|
這個self和cls是對類或者實例的綁定,對於一般的函數來說我們可以這么調用foo(x)
,這個函數就是最常用的,它的工作跟任何東西(類,實例)無關.對於實例方法,我們知道在類里每次定義方法的時候都需要綁定這個實例,就是foo(self, x)
,為什么要這么做呢?因為實例方法的調用離不開實例,我們需要把實例自己傳給函數,調用的時候是這樣的a.foo(x)
(其實是foo(a, x)
).類方法一樣,只不過它傳遞的是類而不是實例,A.class_foo(x)
.注意這里的self和cls可以替換別的參數,但是python的約定是這倆,還是不要改的好.
對於靜態方法其實和普通的方法一樣,不需要對誰進行綁定,唯一的區別是調用的時候需要使用a.static_foo(x)
或者A.static_foo(x)
來調用.
\ | 實例方法 | 類方法 | 靜態方法 |
---|---|---|---|
a = A() | a.foo(x) | a.class_foo(x) | a.static_foo(x) |
A | 不可用 | A.class_foo(x) | A.static_foo(x) |
類的普通方法
class Animal(object): def __init__(self,name): self.name = name def intro(self): print('there is a %s'%(self.name)) cat = Animal('cat') cat.intro()
- 靜態類方法
class Animal(object): def __init__(self,name): self.name = name @staticmethod def intro(self): print('there is a %s'%(self.name)) cat = Animal('cat') cat.intro()
- 加上裝飾器后運行會報錯,原因是方法變為一個普通函數,脫離的與類的關系,不能引用構造函數中的變量了。
使用場景舉例:python內置方法os中的方法,可以直接使用的工具包,跟類沒關系。
class Animal(object): def __init__(self,name): self.name = name @classmethod def intro(self): print('there is a %s'%(self.name)) cat = Animal('cat') cat.intro()
- 報錯信息
如果換成
class Animal(object): name = 'cat' def __init__(self,name): self.name = name @classmethod def intro(self): print('there is a %s'%(self.name)) cat = Animal('cat') cat.intro()
- 可以正常運行。
結論:類方法只能調用類變量,不能調用實例變量
屬性方法@property 把一個方法變為(偽裝成)類屬性。因為類屬性的實質是一個類變量,用戶可以調用變量就可以修改變量。某些特定場景要限制用戶行為,就用到靜態方法。
@property廣泛應用在類的定義中,可以讓調用者寫出簡短的代碼,同時保證對參數進行必要的檢查,這樣,程序運行時就減少了出錯的可能性。(摘自廖雪峰的博客)
class Animal(object): def __init__(self,name): self.name = name @property def intro(self,food): print('there is a %s eating %s'%(self.name,food)) cat = Animal('cat') cat.intro()
- 報錯:
- 方法不能正常調用。如果要調用,如下:
cat.intro
- 是這樣的話,方法就沒辦法單獨傳入參數。如果要傳入參數,如下:
class Animal(object): def __init__(self,name): self.name = name @property def intro(self): print('there is a %s eating %s'%(self.name,food)) @intro.setter def intro(self,food): pass cat = Animal('cat') cat.intro
- cat.intro還有其他操作getter deleter等等。
一:staticmethod
代碼如下:
class Singleton(object): instance = None def __init__(self): raise SyntaxError('can not instance, please use get_instance') @staticmethod def get_instance(): if Singleton.instance is None: Singleton.instance = object.__new__(Singleton) return Singleton.instance a = Singleton.get_instance() b = Singleton.get_instance() print('a id=', id(a)) print('b id=', id(b))該方法的要點是在__init__拋出異常,禁止通過類來實例化,只能通過靜態get_instance函數來獲取實例;因為不能通過類來實例化,所以靜態get_instance函數中可以通過父類object.__new__來實例化。
二:classmethod
和方法一類似,代碼:
class Singleton(object): instance = None def __init__(self): raise SyntaxError('can not instance, please use get_instance') @classmethod def get_instance(cls): if Singleton.instance is None: Singleton.instance = object.__new__(Singleton) return Singleton.instance a = Singleton.get_instance() b = Singleton.get_instance() print('a id=', id(a)) print('b id=', id(b))該方法的要點是在__init__拋出異常,禁止通過類來實例化,只能通過靜態get_instance函數來獲取實例;因為不能通過類來實例化,所以靜態get_instance函數中可以通過父類object.__new__來實例化。
三:類屬性方法
和方法一類似, 代碼:
class Singleton(object): instance = None def __init__(self): raise SyntaxError('can not instance, please use get_instance') def get_instance(): if Singleton.instance is None: Singleton.instance = object.__new__(Singleton) return Singleton.instance a = Singleton.get_instance() b = Singleton.get_instance() print(id(a)) print(id(b))該方法的要點是在__init__拋出異常,禁止通過類來實例化,只能通過靜態get_instance函數來獲取實例;因為不能通過類來實例化,所以靜態get_instance函數中可以通過父類object.__new__來實例化。
四:__new__
常見的方法, 代碼如下:
class Singleton(object): instance = None def __new__(cls, *args, **kw): if not cls.instance: # cls.instance = object.__new__(cls, *args) cls.instance = super(Singleton, cls).__new__(cls, *args, **kw) return cls.instance a = Singleton() b = Singleton() print(id(a)) print(id(b))
五:裝飾器
代碼如下:
def Singleton(cls): instances = {} def getinstance(): if cls not in instances: instances[cls] = cls() return instances[cls] return getinstance @Singleton class MyClass: pass a = MyClass() b = MyClass() c = MyClass() print(id(a)) print(id(b)) print(id(c))
六:元類
python2版:
class Singleton(type): def __init__(cls, name, bases, dct): super(Singleton, cls).__init__(name, bases, dct) cls.instance = None def __call__(cls, *args): if cls.instance is None: cls.instance = super(Singleton, cls).__call__(*args) return cls.instance class MyClass(object): __metaclass__ = Singleton a = MyClass() b = MyClass() c = MyClass() print(id(a)) print(id(b)) print(id(c)) print(a is b) print(a is c)或者:
class Singleton(type): def __new__(cls, name, bases, attrs): attrs["_instance"] = None return super(Singleton, cls).__new__(cls, name, bases, attrs) def __call__(cls, *args, **kwargs): if cls._instance is None: cls._instance = super(Singleton, cls).__call__(*args, **kwargs) return cls._instance class Foo(object): __metaclass__ = Singleton x = Foo() y = Foo() print(id(x)) print(id(y))
python3版:
class Singleton(type): def __new__(cls, name, bases, attrs): attrs['instance'] = None return super(Singleton, cls).__new__(cls, name, bases, attrs) def __call__(cls, *args, **kwargs): if cls.instance is None: cls.instance = super(Singleton, cls).__call__(*args, **kwargs) return cls.instance class Foo(metaclass=Singleton): pass x = Foo() y = Foo() print(id(x)) print(id(y))
七:名字覆蓋
代碼如下:
class Singleton(object): def foo(self): print('foo') def __call__(self): return self Singleton = Singleton() Singleton.foo() a = Singleton() b = Singleton() print(id(a)) print(id(b))