CS 112 › Lesson 2 of 10

Encapsulation & Properties

Lesson 2 · OKSTEM College · Associate of Science in Computer Science

What Is Encapsulation?

Encapsulation bundles data (attributes) and behaviour (methods) together inside a class, and controls which parts are public vs. private. The goal: callers interact through a clean interface, not raw variables.

Name conventions in Python

SyntaxMeaningAccessible from outside?
self.namePublic attributeYes (by convention)
self._nameProtected — "please don't touch"Yes, but discouraged
self.__namePrivate — name-mangled to _ClassName__nameNot directly

Python has no true private. Name-mangling (__x) just makes accidental access harder; determined callers can still reach _ClassName__x.

The @property Decorator

Instead of exposing a raw attribute, define a getter with @property and optionally a setter with @name.setter. This lets you add validation without changing the caller's syntax.

class BankAccount: def __init__(self, balance: float): self._balance = balance # protected storage @property def balance(self) -> float: return self._balance @balance.setter def balance(self, value: float): if value < 0: raise ValueError("Balance cannot be negative") self._balance = value acct = BankAccount(1000) acct.balance = 1500 # calls the setter — clean syntax print(acct.balance) # 1500 — calls the getter acct.balance = -50 # raises ValueError

Worked Example — Temperature Class

Store temperature internally in Celsius as self._celsius.
Add a celsius property with a setter that rejects values below −273.15 (absolute zero).
Add a fahrenheit computed property (no setter needed — it's derived).
Test: create an instance, read both scales, try an invalid value.
class Temperature: def __init__(self, celsius=0): self.celsius = celsius # goes through the setter @property def celsius(self): return self._celsius @celsius.setter def celsius(self, value): if value < -273.15: raise ValueError(f"{value} °C is below absolute zero") self._celsius = value @property def fahrenheit(self): return self._celsius * 9/5 + 32 t = Temperature(100) print(t.fahrenheit) # 212.0 t.celsius = -300 # raises ValueError

Practice Problems

1. Add a fahrenheit setter to Temperature that converts to Celsius and stores via the celsius setter.

@fahrenheit.setter def fahrenheit(self, value): self.celsius = (value - 32) * 5 / 9

2. Write a Circle class with a radius property that rejects negatives, and a computed area property.

import math class Circle: def __init__(self, r): self.radius = r @property def radius(self): return self._r @radius.setter def radius(self, v): if v < 0: raise ValueError self._r = v @property def area(self): return math.pi * self._r ** 2

Knowledge Check

A @property decorator turns a method into a

That would still be calling a method normally.
Correct — you access it as obj.name, no parentheses needed.
Class variables are defined at class level, not with @property.
Static methods use @staticmethod.
Recap: @property lets you call a method as if it were an attribute: obj.balance instead of obj.balance().

What does self.__value (double underscore) do?

Python has no true private; it just name-mangles the identifier.
Correct — this is Python's name-mangling mechanism.
Double underscores don't delete anything.
Class variables are defined outside __init__.
Recap: self.__x is stored as _ClassName__x. It's still accessible, just harder to reach accidentally.

To allow assignment via a property you must add

The decorator name must match: @.setter.
Correct — e.g. @balance.setter defines the setter for the balance property.
A second @property would overwrite the first.
That's a plain setter method, not a property setter.
Recap: pair @property with @name.setter. If you only have the getter, assignment raises AttributeError.

Which attribute naming style signals 'internal use, do not touch from outside'?

That's fully public.
Correct — single underscore is a convention meaning 'protected / internal'.
Trailing underscores are used to avoid keyword conflicts (e.g., class_).
Double underscores on both sides are magic/dunder methods.
Recap: single leading underscore = protected (convention). Double leading underscore = name-mangled (stronger discourage). Dunder = special Python method.

A computed property (like fahrenheit derived from celsius) should

That creates duplication and sync bugs.
That works but breaks encapsulation style; property is cleaner.
Correct — derived values need no storage; calculate on demand.
A setter is only needed if you want to allow assignment through the property.
Recap: computed properties like area or fahrenheit just return a calculation — no backing variable, no setter needed.

← PreviousNext →