4.1.2.3 - Classes, objects and encapsulation (Python)
Learn how classes define state and behaviour, how objects are created and referenced, and how controlled access and different kinds of methods support an object-oriented design.
Classes, fields and methods
A class defines the common attributes and behaviours of a kind of object; each instance can retain its own state.
Class and object
A class defines a type through its attributes and methods. An object is an instance of a class, with identity and state. A method is an operation defined for that class's objects.
A Wallet class can define a balance field and a deposit method. Two wallets use the same class definition but can have different balances. In Python, self names the receiving instance in an ordinary instance method; self.balance refers to that object's field. A local amount parameter is separate from the persistent field. Writing balance = amount inside a method would bind a local name rather than set self.balance.
class Wallet:
def __init__(self, opening):
self.balance = opening
def deposit(self, amount):
self.balance += amount
first = Wallet(10)
second = Wallet(30)
first.deposit(5)
print(first.balance, second.balance)
The output is 15 30. first.deposit(5) supplies first as self and 5 as amount. The second object's state is unchanged. Object-oriented organisation is useful when related behaviour repeatedly acts on each entity's persistent state: a program can manage many wallets through the same operations instead of coordinating parallel variables and unrelated functions. Good classes represent meaningful responsibilities, not merely wrappers around every number.
Instantiation, constructors and references
Instantiation creates a new object, while assigning its reference to another name gives another way to access that same object.
Instantiation is the creation of an object from a class. In first = Wallet(10), calling the class creates the object and invokes __init__ to initialise it. Python's __init__ is the initialiser used in these constructor examples; strictly, object creation happens before it runs. A class with no custom initialiser can use an implicit constructor. The assignment stores a reference in first; Python names do not need a declared class type, although the referenced object has a type.
first = Wallet(10)
alias = first
second = Wallet(10)
alias.deposit(5)
print(first.balance, second.balance)
print(alias is first, second is first)
The output is 15 10 and True False. alias = first copies a reference, not the object. Therefore alias.deposit(5) changes the object also reached by first. The two constructor calls create separate objects even when their initial states match. An object can remain alive after a function returns if its reference is retained elsewhere; losing one local name does not imply losing all references.
Give each instance its own mutable fields. Assigning self.items = [] in __init__ creates a separate list for each instance. A list defined at class level would normally be shared, which is often wrong for per-object contents. A class-level constant, by contrast, may deliberately be common to all instances.
Encapsulation and access
Encapsulation keeps related state and operations together and controls how clients use that state.
Encapsulation
Bundling an object's state with its operations, and hiding implementation details behind an agreed public interface so state changes can preserve the object's rules.
For a wallet, the rule might be that the balance is never negative. A public withdraw(amount) can check funds before changing it; allowing every caller to assign a balance directly makes that rule harder to maintain. A property can expose a read-only balance while methods perform controlled updates.
| Access in a class design | Intended users | UML symbol | Python approach |
|---|---|---|---|
| Public | Clients of the class | + | Ordinary names such as deposit |
| Private | Class's implementation | - | __balance name mangling; not absolute protection |
| Protected | Class and subclasses | # | _balance convention; not enforced access control |
Python has no Java/C#-style enforced public/private/protected specifiers. A single leading underscore signals non-public use by convention. A double leading underscore mangles a name to reduce accidental clashes, especially with subclasses; it does not make access impossible. UML expresses the intended design, not a claim that every Python access is blocked by the runtime.
Continue this lesson.
You’re previewing NovaLearn without an account. Create a free account to read the rest.
Create free account