关于python:getter和setter的Google Style Guide属性

Google Style Guide properties for getters and setters

我对google 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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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

关于这一点,我有两个问题:

  • 与直接使用两个下划线相比,使用三个下划线"间接"___get_area___set_area以及两个下划线有什么好处?

  • 为什么使用property()作为一个方法,使用这组双下划线和三下划线方法,而不是执行以下操作:

    1
    2
    3
    4
    5
    6
    7
    @property
    def area(self):
        return self.side ** 2

    @area.setter
    def area(self, value):
        self.side = math.sqrt(value)

  • 在样式指南中,他们给出了一个原因:

    Inheritance with properties can be non-obvious if the property itself is not overridden. Thus one must make sure that accessor methods are called indirectly to ensure methods overridden in subclasses are called by the property (using the Template Method DP).

    (模板方法dp是模板方法设计模式(Alex Martelli的幻灯片,谷歌的pythonista Extraordinaire)。

    因此,它们希望给子类机会重写实现,并给property三下划线版本调用双下划线方法,以便您可以重写这些方法。在这种情况下,你必须拼出损坏的名字:

    1
    2
    3
    class WonkySquare(Square):
        def _Square__get_area(self):
            return self.square ** 2 + 0.5

    显然,提出此方案的人从来就不知道您可以只覆盖属性的getter或setter,请参见python overriding getter without setter:

    1
    2
    3
    4
    class ProperlySubclassedSquare(Square):
        @Square.area.getter
        def area(self):
            return self.square ** 2 + (0.5 - 0.5)

    然后,在python 2.6中只添加了gettersetterdeleter装饰器属性。样式指南必须是为旧的Python版本编写的。

    对于2.6及更高版本,请遵循@propname.setter模式。