作者sandwichC (没回应=挂站)
看板Translate-CS
标题Fw: [翻译] Google 建议的 Python 风格指南 13
时间Wed May 8 00:26:24 2013
※ [本文转录自 Python 看板 #1HYIhEj7 ]
作者: sandwichC (没回应=挂站) 看板: Python
标题: [翻译] Google 建议的 Python 风格指南 13
时间: Wed May 8 00:24:43 2013
欢迎大家插队翻译,像 t 大那篇就写得很棒
有时候翻译的过程发现一些以前没注意的小细节也蛮有趣的
这次的内容是用 property 读写 class 内的变数
对 property 不熟的可以搭配 python doc 阅读:
http://docs.python.org/2/library/functions.html#property
-------正文开始的分隔线-------
原文网址:
http://google-styleguide.googlecode.com/svn/trunk/pyguide.html
属性 (property)
若需要读写类别内的变数时,使用 属性 (property) 来取代直接的存取及
getter/setter 式的存取。
释义:
它是 getter/setter 的一个包装 (wrapper)。使用 a.x 时,虽然看起来像是直接
读写,但实际上是透过类似於 a.setX(val) 或 a.getX() 的方式来读写,当计算
量不大时适用。
优点:
不需要使用 getter 及 setter,故可读性增加。计算采用延迟求值的方式 (lazy
calculation)。这是 python 在写 class 时的惯用法 (编案:较旧版本的 python
不支援此方法)。有时候直接读写类别内的变数是合理的,这时使用 getter/setter
的方法显得繁琐。若使用属性则可绕过这个问题,未来也可以在不破坏呼叫方式的
情况下加上读写的方法 (method)。
缺点:
使用上,property 宣告的地方在 getter 与 setter 方法之後,因此往往得看到
後面的程式片段才知道前面的方法被用来当作属性。例外:唯读的属性在被创建
的时候就有 @property 的装饰 (decorator) 了,最後有例子。(编案:较新的
python 多了 setter 和 deleter 的 decorator,所以这已经不是缺点了。)
必须继承自 object 类别。可能隐藏像是运算子重载这类的副作用。继承时易造
成困惑。
决策:
在新的程式中用 property 来取代直接读写或 getter/setter 式的读写。唯读的
property 在创建时加上 @property 装饰。
(编案:较新的版本的 python 可直接用 @property, @x.setter, @x.deleter
来取代 x = property(getx, setx, delx, "docstring contents"))
继承时,若子类别没覆载 (override) property,则继承关系很模糊。
因此,应确认读写的方法被间接地呼叫,以确保子类别中被重载的方法有被
property 呼叫。(使用 template method 设计模式)
(编案:若子类别连 property 一起覆载,则不一定需要用 template method 设
计模式间接呼叫读写的方法。)
Yes:
import math
class Square(object):
"""A square with two properties: a writable area and a read-only perimeter.
To use:
>>> sq = Square(3)
>>> sq.area
9
>>> sq.perimeter
12
>>> sq.area = 16
>>> sq.side
4
>>> sq.perimeter
16
"""
def __init__(self, side):
self.side = side
def __get_area(self):
"""Calculates the 'area' property."""
return self.side ** 2
def ___get_area(self):
"""Indirect accessor for 'area' property."""
return self.__get_area()
def __set_area(self, area):
"""Sets the 'area' property."""
self.side = math.sqrt(area)
def ___set_area(self, area):
"""Indirect setter for 'area' property."""
self.__set_area(area)
area = property(___get_area, ___set_area,
doc="""Gets or sets the area of the square.""")
@property
def perimeter(self):
return self.side * 4
编案:以下的例子可以帮助理解为何有子类别时要使用间接呼叫
(1) 不使用间接呼叫
class Foo(object):
def _get_var(self):
return 10
var = property(_get_var)
class Bar(Foo):
def _get_var(self):
return 20
bar = Bar()
print bar.var
输出:10
(2) 使用间接呼叫
class Foo(object):
def _get_var(self):
return 10
def __get_var(self):
return self._get_var()
var = property(__get_var)
class Bar(Foo):
def _get_var(self):
return 20
bar = Bar()
print bar.var
输出:20
(3) 子函式也用 property
class Foo(object):
def _get_var(self):
return 10
var = property(_get_var)
class Bar(Foo):
def _get_var(self):
return 20
var = property(_get_var)
bar = Bar()
print bar.var
输出:20
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 75.102.68.185
※ 发信站: 批踢踢实业坊(ptt.cc)
※ 转录者: sandwichC (75.102.68.185), 时间: 05/08/2013 00:26:24