1. 程式人生 > >Python @property

Python @property

temp iter com 解決 需要 想要 all most last

Fluent Python 9.6節講到hashable Class,

為了使Vector2d類可散列,有以下條件:

(1)實現__hash__方法

(2)實現__eq__方法

(3)讓Vector2d向量不可變

如何讓Vector2d類實例的向量只讀呢?可以使用property,如下所示:

class Vector2d:
    def __init__(self, x, y):
        self._x = x
        self.__y = y

    @property  # The @property decorator marks the getter method of a property.
def x(self): return self._x @property # The @property decorator marks the getter method of a property. def y(self): return self.__y def __hash__(self): return hash(self._x) ^ hash(self.__y) def __eq__(self, other): return hash(self) == hash(other)
def __iter__(self): return (i for i in (self._x, self.__y))

我們在控制臺嘗試修改x或者y:

>>> import Example9_7
>>> v1 = Example9_7.Vector2d(3, 4)
>>> v1.x 
3
>>> v1.x = 4
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can
t set attribute >>> v1.y = 5 Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: cant set attribute

這是我們想要的行為,但是為什麽加上@properly裝飾器後就變為只讀了呢?我們需要對property有更深入的了解。

An Example To Begin With:

在此之前,我們先來看看property的應用場景:

假設我們寫了一個關於溫度的類:

class Celsius:
    def __init__(self, temperature=0):
        self.temperature = temperature

    def get_fahrenheit(self):
        return self.temperature * 1.8 + 32

並且這個類漸漸變的很流行,被很多用戶所調用,有一天,一個用戶跑來建議說,溫度不應該低於絕對溫度-273攝氏度,他要求我們實現這個限制。

為了這樣實現用戶的要求,我們更新為v1.1:

class Celsius:
    def __init__(self, temperature=0):
        self.__temperature = temperature

    def get_fahrenheit(self):
        return self.__temperature * 1.8 + 32
    
    def get_temperature(self):
        return self.__temperature

    def set_temperature(self, value):
        if value < -273:
            raise ValueError("Temperature below -273 is not possible.")
        self.__temperature = value

用戶的要求是實現了 可以這裏有個問題,用戶的代碼裏任然是這樣獲取溫度的:

c = Celsius(37)
c.temperature = 20 current_temperature
= c.temperature

而且代碼裏有成百上千行如此的代碼,這些代碼不得不改為:

c.set_temperature(20)
c.get_temperature()

對於用戶來說這是很頭疼的問題,因為我們的修改不是backward compatible.

The Power of @property:

對於這個問題,更為Pythonic解決方式如下:

 1 class Celsius:
 2     def __init__(self, temperature=0):
 3         self.__temperature = temperature
 4 
 5     def get_fahrenheit(self):
 6         return self.__temperature * 1.8 + 32
 7 
 8     def get_temperature(self):
 9         return self.__temperature
10 
11     def set_temperature(self, value):
12         if value < -273:
13             raise ValueError("Temperature below -273 is not possible.")
14         self.__temperature = value
15 
16     temprature = property(get_temperature, set_temperature)

這樣,用戶任然像以前一樣訪問temprature:

>>> c1 = property_demo.Celsius(10)
>>> c1.temprature
10
>>> c1.temprature = 20
>>> c1.temprature
20

因此我們既實現了對termperature的限制,有保證了向後兼容

Digging Deeper into Property:

Python @property