@property as managed attributes
@property turns a method into a read-only attribute. Callers write obj.temperature instead of obj.temperature(). The class controls what gets returned, but the public interface looks like a plain attribute.
A matching @<name>.setter lets the class run code when the attribute is assigned. This is where you put validation: rejecting impossible values, converting input units, normalizing data. The caller still writes obj.temperature = -300, and the setter decides whether to accept it.
The pattern lets you start with a plain attribute and upgrade to a managed one later, without breaking any callers. That is the main reason Python avoids the explicit getter/setter culture you see in some other languages.