Python has a really nifty feature: if you write a method that takes no arguments other than self
or cls
and add a @property
decorator to it, it is then referenced without parentheses, like an attribute. This allows you to perform some work on the fly without the “cruft” of ()
, which can be rather ergonomic:
>>> class Rectangle:
... height: int
... width: int
... def __init__(self, height, width):
... self.height = height
... self.width = width
... @property
... def area(self):
... return self.height * self.width
...
>>> rectangle = Rectangle(height=3, width=4)
>>> rectangle.area
12
I often find myself using properties as boolean flags:
>>> class Rectangle:
... height: int
... width: int
... def __init__(self, height, width):
... self.height = height
... self.width = width
... @property
... def is_square(self):
... return self.height == self.width
...
>>> rectangle = Rectangle(height=3, width=4)
>>> rectangle.is_square
False
>>> square = Rectangle(height=5, width=5)
>>> square.is_square
True
It gets a bit dicey when I occasionally forget the @property
decorator, because the existence of a method is truthy:
>>> class Rectangle:
... height: int
... width: int
... def __init__(self, height, width):
... self.height = height
... self.width = width
... # @property
... def is_square(self):
... return self.height == self.width
...
>>> rectangle = Rectangle(height=3, width=4)
>>> rectangle.is_square
<bound method Rectangle.is_quare of <__main__.Rectangle object at 0x1030f1120>>
>>> bool(rectangle.is_square)
True
>>> if rectangle.is_square:
... print(f"Rectangle {rectangle.height}x{rectangle.width} is a square.")
...
Rectangle 3x4 is a square.
So yeah, don’t forget the decorator.
Brought to you by my having this exact problem earlier today.
Thanks for reading! You can keep up with my writing via the feed or newsletter, or you can get in touch via email or Mastodon.