Python中有一個被稱為屬性函式(property)的小概念,它可以做一些有用的事情。在這篇文章中,我們將看到如何能做以下幾點:
- 將類方法轉換為只讀屬性
- 重新實現一個屬性的setter和getter方法
在本文中,您將學習如何以幾種不同的方式來使用內建的屬性函式。希望讀到文章的末尾時,你能看到它是多麼有用。
開始
使用屬性函式的最簡單的方法之一是將它作為一個方法的裝飾器來使用。這可以讓你將一個類方法轉變成一個類屬性。當我需要做某些值的合併時,我發現這很有用。其他想要獲取它作為方法使用的人,發現在寫轉換函式時它很有用。讓我們來看一個簡單的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
######################################################################## class Person(object): """""" #---------------------------------------------------------------------- def __init__(self, first_name, last_name): """Constructor""" self.first_name = first_name self.last_name = last_name #---------------------------------------------------------------------- @property def full_name(self): """ Return the full name """ return "%s %s" % (self.first_name, self.last_name) |
在上面的程式碼中,我們建立了兩個類屬性:self.first_name和self.last_name。接下來,我們建立了一個full_name方法,它有一個@property裝飾器。這使我們能夠在Python直譯器會話中有如下的互動:
1 2 3 4 5 6 7 8 9 |
>>> person = Person("Mike", "Driscoll") >>> person.full_name 'Mike Driscoll' >>> person.first_name 'Mike' >>> person.full_name = "Jackalope" Traceback (most recent call last): File "<string>", line 1, in <fragment> AttributeError: can't set attribute |
正如你所看到的,因為我們將方法變成了屬性,我們可以使用正常的點符號訪問它。但是,如果我們試圖將該屬性設為其他值,我們會引發一個AttributeError錯誤。改變full_name屬性的唯一方法是間接這樣做:
1 2 3 |
>>> person.first_name = "Dan" >>> person.full_name 'Dan Driscoll' |
這是一種限制,因此讓我們來看看另一個例子,其中我們可以建立一個允許設定的屬性。
使用Python property取代setter和getter方法
讓我們假設我們有一些遺留程式碼,它們是由一些對Python理解得不夠好的人寫的。如果你像我一樣,你之前已經看到過這類的程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
from decimal import Decimal ######################################################################## class Fees(object): """""" #---------------------------------------------------------------------- def __init__(self): """Constructor""" self._fee = None #---------------------------------------------------------------------- def get_fee(self): """ Return the current fee """ return self._fee #---------------------------------------------------------------------- def set_fee(self, value): """ Set the fee """ if isinstance(value, str): self._fee = Decimal(value) elif isinstance(value, Decimal): self._fee = value |
要使用這個類,我們必須要使用定義的getter和setter方法:
1 2 3 4 |
>>> f = Fees() >>> f.set_fee("1") >>> f.get_fee() Decimal('1') |
如果你想新增可以使用正常點符號訪問的屬性,而不破壞所有依賴於這段程式碼的應用程式,你可以通過新增一個屬性函式非常簡單地改變它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
from decimal import Decimal ######################################################################## class Fees(object): """""" #---------------------------------------------------------------------- def __init__(self): """Constructor""" self._fee = None #---------------------------------------------------------------------- def get_fee(self): """ Return the current fee """ return self._fee #---------------------------------------------------------------------- def set_fee(self, value): """ Set the fee """ if isinstance(value, str): self._fee = Decimal(value) elif isinstance(value, Decimal): self._fee = value fee = property(get_fee, set_fee) |
我們在這段程式碼的末尾新增了一行。現在我們可以這樣做:
1 2 3 4 5 6 7 |
>>> f = Fees() >>> f.set_fee("1") >>> f.fee Decimal('1') >>> f.fee = "2" >>> f.get_fee() Decimal('2') |
正如你所看到的,當我們以這種方式使用屬性函式時,它允許fee屬性設定並獲取值本身而不破壞原有程式碼。讓我們使用屬性裝飾器來重寫這段程式碼,看看我們是否能得到一個允許設定的屬性值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
from decimal import Decimal ######################################################################## class Fees(object): """""" #---------------------------------------------------------------------- def __init__(self): """Constructor""" self._fee = None #---------------------------------------------------------------------- @property def fee(self): """ The fee property - the getter """ return self._fee #---------------------------------------------------------------------- @fee.setter def fee(self, value): """ The setter of the fee property """ if isinstance(value, str): self._fee = Decimal(value) elif isinstance(value, Decimal): self._fee = value #---------------------------------------------------------------------- if __name__ == "__main__": f = Fees() |
上面的程式碼演示瞭如何為fee屬性建立一個setter方法。你可以用一個名為@fee.setter的裝飾器裝飾第二個方法名也為fee的方法來實現這個。當你如下所做時,setter被呼叫:
1 2 |
>>> f = Fees() >>> f.fee = "1" |
如果你看屬性函式的說明,它有fget, fset, fdel和doc幾個引數。如果你想對屬性使用del命令,你可以使用@fee.deleter建立另一個裝飾器來裝飾相同名字的函式從而實現刪除的同樣效果。
結束語
現在你知道如何在你的類中使用Python的屬性函式。希望你能找到更有用的方式,在你的程式碼中使用它們。
補充閱讀:
- Python中的getter和setter方法
- 官方Python文件中對property的介紹
- StackOverflow中對給Python屬性函式增加文件字串的一個討論