天天看點

python @ @classmethod @staticmethod @property轉載自

轉載自

http://www.cnblogs.com/elie/p/5876210.html

http://www.360doc.com/content/14/0811/11/16044571_400987060.shtml

1. python中@classmethod  @staticmethod差別

Python中3種方式定義類方法, 正常方式, @classmethod修飾方式, @staticmethod修飾方式.

class A(object):
    def foo(self, x):
        print("executing foo(%s,%s)" % (self, x))
        print('self:', self)
    @classmethod
    def class_foo(cls, x):
        print("executing class_foo(%s,%s)" % (cls, x))
        print('cls:', cls)
    @staticmethod
    def static_foo(x):
        print("executing static_foo(%s)" % x)    
a = A()
           

1.定義方式

普通的類方法foo()需要通過self參數隐式的傳遞目前類對象的執行個體。 @classmethod修飾的方法class_foo()需要通過cls參數傳遞目前類對象。@staticmethod修飾的方法定義與普通函數是一樣的。

self和cls的差別不是強制的,隻是PEP8中一種程式設計風格,slef通常用作執行個體方法的第一參數,cls通常用作類方法的第一參數。即通常用self來傳遞目前類對象的執行個體,cls傳遞目前類對象。

2.綁定對象

foo方法綁定對象A的執行個體,class_foo方法綁定對象A,static_foo沒有參數綁定。
                
>>> print(a.foo)
<bound method A.foo of <__main__.A object at 0x0278B170>>
>>> print(a.class_foo)
<bound method A.class_foo of <class '__main__.A'>>
>>> print(a.static_foo)
<function A.static_foo at 0x02780390>
           

3.調用方式

foo可通過執行個體a調用,類對像A直接調用會參數錯誤。

>>> a.foo(1)
executing foo(<__main__.A object at 0x0278B170>,1)
self: <__main__.A object at 0x0278B170>
>>> A.foo(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() missing 1 required positional argument: 'x'
           

但foo如下方式可以使用正常,顯式的傳遞執行個體參數a。

>>> A.foo(a, 1)
executing foo(<__main__.A object at 0x0278B170>,1)
self: <__main__.A object at 0x0278B170>                

class_foo通過類對象或對象執行個體調用。

>>> A.class_foo(1)
executing class_foo(<class '__main__.A'>,1)
cls: <class '__main__.A'>
>>> a.class_foo(1)
executing class_foo(<class '__main__.A'>,1)
cls: <class '__main__.A'>                

static_foo通過類對象或對象執行個體調用。

>>> A.static_foo(1)
executing static_foo(1)
>>> a.static_foo(1)
executing static_foo(1)                

4.繼承與覆寫普通類函數是一樣的。

class B(A):
    pass
b = B()
b.foo(1)
b.class_foo(1)
b.static_foo(1)
# executing foo(<__main__.B object at 0x007027D0>,1)
# self: <__main__.B object at 0x007027D0>
# executing class_foo(<class '__main__.B'>,1)
# cls: <class '__main__.B'>
# executing static_foo(1)
           

問題:@staticmethod修飾的方法函數與普通的類外函數,為什麼不直接使用普通函數?

@staticmethod是把函數嵌入到類中的一種方式,函數就屬于類,同時表明函數不需要通路這個類。通過子類的繼承覆寫,能更好的組織代碼。

2. python中的@符号

@就是python中的修飾器,裝飾器(Decorators)是 Python 的一個重要部分。簡單地說:他們是修改其他函數的功能的函數。他們有助于讓我們的代碼更簡短,也更Pythonic(Python範兒)。簡而言之,修飾器封裝一個函數,并且用這樣或者那樣的方式來修改它的行為,使得在這個函數運作之前或者之後執行某些動作。

詳細解讀見:https://blog.csdn.net/xiaojiajia007/article/details/96433150

def minus(f):

    print 'minus'

    f()

def plus(f):

    print 'plus'

    f()

def test(a):

    if a > 3 :return plus

    else: return minus

@test(5)  

def xxx():

    print 'ok'

# 解釋器 首先會解釋    @符号後面的代碼,如果和上面的代碼類似,那麼test(5)将會被執行,因為5>3,是以

#會傳回一個函數指針plus, plus将下一行的函數指針xxx當作參數傳入,直到執行完成。最後輸出:

# plus ok

def minus(f):

    print 'minus'

    f()

@minus

def xxx():

    print 'ok'

# minus本身就已經是一個函數指針,是以會直接以xxx作為參數傳入,結果會輸出

# minus,ok

3. python中的屬性修飾器  @property   

一個例子如下,下面是一個property class:

class Parrot:
    def __init__(self):
        self._voltage = 100000

    @property
    def voltage(self):
        """Get the current voltage."""
        return self._voltage
           

The @property decorator turns the voltage() method into a “getter” for a read-only attribute with the same name, and it sets the docstring for voltage to “Get the current voltage.” 也就是說這麼做,就可以生成一個變量名為voltage,且值為100000的隻讀(read-only)屬性(attribute)。若執行個體化一個 p = Parrot(), 則p.voltage=100000,不能改變,若需要改變,需要使用setter. 

轉載自:https://www.cnblogs.com/Lambda721/p/6132206.html

考察 Student 類:

class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score
           

當我們想要修改一個 Student 的 scroe 屬性時,可以這麼寫:

s = Student('Bob', 59)
s.score = 60
           

但是也可以這麼寫:

s.score = 1000
           

顯然,直接給屬性指派無法檢查分數的有效性。

如果利用兩個方法:

class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.__score = score
    def get_score(self):
        return self.__score
    def set_score(self, score):
        if score < 0 or score > 100:
            raise ValueError('invalid score')
        self.__score = score
           

這樣一來,s.set_score(1000) 就會報錯。

這種使用 get/set 方法來封裝對一個屬性的通路在許多面向對象程式設計的語言中都很常見。

但是寫 s.get_score() 和 s.set_score() 沒有直接寫 s.score 來得直接。

有沒有兩全其美的方法?----有。

因為Python支援高階函數,可以用裝飾器函數把 get/set 方法“裝飾”成屬性調用:

class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.__score = score
    @property
    def score(self):
        return self.__score
    @score.setter
    def score(self, score):
        if score < 0 or score > 100:
            raise ValueError('invalid score')
        self.__score = score
           

注意: 第一個score(self)是get方法,用@property裝飾,第二個score(self, score)是set方法,用@score.setter裝飾,@score.setter是前一個@property裝飾後的副産品。

現在,就可以像使用屬性一樣設定score了:

>>> s = Student('Bob', 59)
>>> s.score = 60
>>> print s.score
60
>>> s.score = 1000
Traceback (most recent call last):
  ...
ValueError: invalid score
           

說明對 score 指派實際調用的是 set方法。

另一個例子  點選打開連結

注意到這個神奇的@property,我們在對執行個體屬性操作的時候,就知道該屬性很可能不是直接暴露的,而是通過getter和setter方法來實作的。

還可以定義隻讀屬性,隻定義getter方法,不定義setter方法就是一個隻讀屬性。

下面的birth是可讀寫屬性,而age就是一個隻讀屬性,因為age可以根據birth和目前時間計算出來。

class Student(object):
 
  @property
  def birth(self):
    return self._birth
 
  @birth.setter
  def birth(self, value):
    self._birth = value
 
  @property
  def age(self):
    return 2014 - self._birth
           

@property廣泛應用在類的定義中,可以讓調用者寫出簡短的代碼,同時保證對參數進行必要的檢查,這樣,程式運作時就減少了出錯的可能性。