I'm curious about one of the recommendations in the Google Python style guide concerning properties.
In it, they give the following example:
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
I have two questions about this:
What is the benefit of using the three underscore "indirection"
___get_area
and___set_area
as well as two underscore ones, over just using the two underscore ones directly?Why use
property()
as a method with this set of double and triple underscore methods, rather than doing something like:@property def area(self): return self.side ** 2 @area.setter def area(self, value): self.side = math.sqrt(value)
In the style guide they do give a reason:
(where Template Method DP is the Template Method Design Pattern (slides by Alex Martelli, Pythonista extraordinaire at Google).
So they want to give subclasses the chance to override the implementation, and give the
property
the triple-underscore versions to call the double-underscore methods so you can override these. You'd have to spell out the mangled name in that case:Apparently the people that came up with this scheme never knew that you can override just a getter or setter of a property, see Python overriding getter without setter:
Then again, the
getter
,setter
anddeleter
decorator attributes were only added in Python 2.6. The style guide must've been written for an older Python version.For 2.6 and up, stick to the
@propname.setter
pattern instead.