python-靜態方法staticmethod、類方法classmethod、屬性方法property


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

 


免責聲明!

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



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