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))
