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
Syntax
Meaning
Accessible from outside?
self.name
Public attribute
Yes (by convention)
self._name
Protected — "please don't touch"
Yes, but discouraged
self.__name
Private — name-mangled to _ClassName__name
Not 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.
classBankAccount:
def__init__(self, balance: float):
self._balance = balance # protected storage@propertydefbalance(self) -> float:
returnself._balance
@balance.setterdefbalance(self, value: float):
if value < 0:
raiseValueError("Balance cannot be negative")
self._balance = value
acct = BankAccount(1000)
acct.balance = 1500# calls the setter — clean syntaxprint(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.
classTemperature:
def__init__(self, celsius=0):
self.celsius = celsius # goes through the setter@propertydefcelsius(self):
returnself._celsius
@celsius.setterdefcelsius(self, value):
if value < -273.15:
raiseValueError(f"{value} °C is below absolute zero")
self._celsius = value
@propertydeffahrenheit(self):
returnself._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.
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.