Encapsulation
مُقدَّم| English | المعنى |
|---|---|
| invariant/ɪnˈveərɪənt/ | A property required to remain true at specified points, such as before and after public method calls. |
| encapsulation/ɪnˌkæpsjʊˈleɪʃn/ | Grouping data with the operations that use it and controlling access through an interface. |
| interface/ˈɪntəfeɪs/ | The operations and contracts through which other code uses an object or component. |
Out to two borrowers at once
- The library records say one copy is out to two borrowers at the same time. No method in the program can produce that state, so where did it come from?
- Someone reached past the methods and changed the data directly. This lesson is about building a wall that stops that.
Every class has an invariant
- An invariant 不变量 is a statement that is true between calls. For a library copy: it is either on the shelf or out to exactly one borrower, nothing else.
- Every method may break it for a moment inside, but must leave it true when it returns.
Encapsulation
- Encapsulation 封装 keeps the invariant true: the data is private and every change goes through methods that check it. Those public methods are the class's interface 接口.
- A leading underscore (
_out) marks internal data. It is a convention, not a lock, so the discipline is on the callers.
def issue(self):
if self._out:
raise ValueError('already out')
self._out = True
Calling issue() on a copy that is already out —
الصعوبة 1/5 · 100 عملة + مكافأة صغيرة عند الإنجاز الأول اليوم
The guard raises before any change is made — check-first means failed calls corrupt nothing.
In Python, a leading underscore stops other code from changing the attribute.
الصعوبة 1/5 · 100 عملة + مكافأة صغيرة عند الإنجاز الأول اليوم
It is only a convention that says "internal". Nothing stops a caller, so the discipline matters.
Why one gate is enough
- If every change to
_outgoes throughissueandgive_back, you can prove the invariant by reading just those two short methods. - Add one unchecked writer anywhere and the proof is gone: the places to check now grow with every caller.

Put the steps of a safe state-changing method in order.
الصعوبة 3/5 · 200 عملة + مكافأة صغيرة عند الإنجاز الأول اليوم
Checking first means a failed call leaves the object exactly as it was.
The cost of a leak
- A teammate writes
c._out = 'y': truthy, but notTrue. One caller (if c.is_out():) treats the copy as out; another (if c.is_out() is True:) treats it as available. - Two readers now disagree about one object. Fixing it means checking every reader; the check would have cost two
ifstatements.
Writing c._out = y from outside breaks readers because —
الصعوبة 1/5 · 100 عملة + مكافأة صغيرة عند الإنجاز الأول اليوم
y is truthy but is not True, so if is_out(): and if is_out() is True: give different answers.
Expose behaviour, not storage
- Returning an internal list (
return self._loans) hands callers your private data to change. Return a copy instead. - Offer actions such as
available(), not a getter and setter for every field: get/set pairs for everything is not encapsulation.
Returning the internal list directly is risky because —
الصعوبة 1/5 · 100 عملة + مكافأة صغيرة عند الإنجاز الأول اليوم
The caller holds the very list your invariant depends on — return a copy instead.
A library holds 3 loans and its loans() method returns self._loans. A caller appends 2 items to the list it got back. How many loans does the library now hold?
الصعوبة 2/5 · 140 عملة + مكافأة صغيرة عند الإنجاز الأول اليوم
The caller changed the library's own list. Returning list(self._loans) would have kept it at 3.
Match each line of code to what it does to encapsulation.
الصعوبة 2/5 · 140 عملة + مكافأة صغيرة عند الإنجاز الأول اليوم
Expose actions and copies; keep the real data behind the wall.
Worked example: the wall holds
c.issue()succeeds. A secondc.issue()raisesValueError, and the object is unchanged: the check comes first, so nothing needs undoing.c.give_back(), thenc.issue()works again._outis only everTrueorFalse.
Three common slips
- Returning the internal list. Callers can then change your private state.
- Checking in the constructor but not in the setter. Every way in needs the same check.
- Writing get/set pairs for everything. That publishes the storage; publish behaviour instead.
Recap
- An invariant is true between calls; encapsulation keeps it true.
- An underscore marks private data; public methods check every change at the gate.
- Check first so failed calls change nothing; return copies; expose behaviour, not fields.