# 属性 ## 只读属性 只读属性,顾名思义,指的是只可读不可写的属性,之前我们定义的属性都是可读可写的,对于只读属性,我们需要使用 `@property` 修饰符来得到: In [1]: ```py class Leaf(object): def __init__(self, mass_mg): self.mass_mg = mass_mg # 这样 mass_oz 就变成属性了 @property def mass_oz(self): return self.mass_mg * 3.53e-5 ``` 这里 `mass_oz` 就是一个只读不写的属性(注意是属性不是方法),而 `mass_mg` 是可读写的属性: In [2]: ```py leaf = Leaf(200) print leaf.mass_oz ``` ```py 0.00706 ``` 可以修改 `mass_mg` 属性来改变 `mass_oz`: In [3]: ```py leaf.mass_mg = 150 print leaf.mass_oz ``` ```py 0.005295 ``` 是属性不是方法: In [4]: ```py leaf.mass_oz() ``` ```py --------------------------------------------------------------------------- TypeError Traceback (most recent call last) in () ----> 1 leaf.mass_oz() TypeError: 'float' object is not callable ``` 而且是只读属性,不可写: In [5]: ```py leaf.mass_oz = 0.001 ``` ```py --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) in () ----> 1 leaf.mass_oz = 0.001 AttributeError: can't set attribute ``` 回到 `forest` 的例子,我们希望加入几个只读属性: In [6]: ```py import numpy as np class Forest(object): """ Forest can grow trees which eventually die.""" def __init__(self, size=(150,150)): self.size = size self.trees = np.zeros(self.size, dtype=bool) self.fires = np.zeros((self.size), dtype=bool) def __repr__(self): my_repr = "{}(size={})".format(self.__class__.__name__, self.size) return my_repr def __str__(self): return self.__class__.__name__ @property def num_cells(self): """Number of cells available for growing trees""" return np.prod(self.size) @property def tree_fraction(self): """ Fraction of trees """ num_trees = self.trees.sum() return float(num_trees) / self.num_cells @property def fire_fraction(self): """ Fraction of fires """ num_fires = self.fires.sum() return float(num_fires) / self.num_cells ``` 查看属性: In [7]: ```py forest = Forest() forest.num_cells ``` Out[7]: ```py 22500 ``` 生成一个较小的森林: In [8]: ```py small_forest = Forest((10, 10)) small_forest.num_cells ``` Out[8]: ```py 100 ``` 初始状态下,树和火灾的比例都是 0: In [9]: ```py small_forest.tree_fraction ``` Out[9]: ```py 0.0 ``` In [10]: ```py small_forest.fire_fraction ``` Out[10]: ```py 0.0 ``` ## 可读写的属性 对于 `@property` 生成的只读属性,我们可以使用相应的 `@attr.setter` 修饰符来使得这个属性变成可写的: In [11]: ```py class Leaf(object): def __init__(self, mass_mg): self.mass_mg = mass_mg # 这样 mass_oz 就变成属性了 @property def mass_oz(self): return self.mass_mg * 3.53e-5 # 使用 mass_oz.setter 修饰符 @mass_oz.setter def mass_oz(self, m_oz): self.mass_mg = m_oz / 3.53e-5 ``` 测试: In [12]: ```py leaf = Leaf(200) print leaf.mass_oz leaf.mass_mg = 150 print leaf.mass_oz ``` ```py 0.00706 0.005295 ``` 修改 `mass_oz` 属性: In [13]: ```py leaf.mass_oz = 0.01 print leaf.mass_mg ``` ```py 283.28611898 ``` 一个等价的替代如下: ```py class Leaf(object): def __init__(self, mass_mg): self.mass_mg = mass_mg def get_mass_oz(self): return self.mass_mg * 3.53e-5 def set_mass_oz(self, m_oz): self.mass_mg = m_oz / 3.53e-5 mass_oz = property(get_mass_oz, set_mass_oz) ```