Objects & Classes
A class is a blueprint for creating objects that bundle data (fields/attributes) and behavior (methods) together. This section introduces the essential vocabulary; the full depth of object-oriented programming — inheritance, polymorphism, SOLID principles, and design patterns — is covered in the future dedicated Object-Oriented Programming module.
A class defines a blueprint describing what data (fields) and behavior (methods) its instances will have. An object is one specific instance created from that class — each object has its own copy of the class's fields, but shares the same defined methods.
Bundling related data and the behavior that operates on it into a single unit keeps code organized and makes it easier to model real-world (or conceptual) things directly — a Car object naturally has both data (speed, fuel level) and behavior (accelerate(), refuel()) that belong together.
Modeling a bank account (balance, deposit(), withdraw()), a user profile (name, email, updateEmail()), a game character (health, position, takeDamage()), or a UI button (label, onClick()) — object-oriented modeling is used pervasively across application development.
A class is like a cookie cutter — a single fixed shape/template. An object is an actual cookie made using that cutter — each cookie (object) is separate and can be decorated differently (have different field values), but they all share the same fundamental shape defined by the cutter (the class's structure and behavior).
Dog is the class (blueprint). my_dog = Dog("Rex") creates one specific object (instance) of that class, with its own name field set to "Rex". Calling my_dog.bark() runs the shared bark method, using that particular object's own data.
A constructor is a special method that runs automatically when a new object is created, typically used to initialize the object's fields (Python's __init__, Java/C++'s constructor matching the class name) — some languages also have a destructor, run when an object is destroyed, used to release resources it was holding.
Encapsulation means bundling an object's internal data together with the methods that operate on it, and often deliberately restricting direct outside access to some of that internal data (via private/protected visibility) so it can only be modified through controlled methods — protecting the object's internal consistency.
Inheritance lets one class (a subclass/derived class) reuse and extend another class's (a superclass/base class) fields and methods, modeling an 'is-a' relationship (a Dog is an Animal). Composition instead builds a class out of other objects as fields, modeling a 'has-a' relationship (a Car has an Engine) — both are covered fully in the future Object-Oriented Programming module, including the important trade-offs between them.
Polymorphism, broadly, means code can work with objects of different concrete types through a shared interface, without needing to know the exact concrete type in advance — for example, calling a shared makeSound() method on a list of different Animal subclasses and having each one behave according to its own specific implementation.
Making all of a class's fields publicly accessible with no encapsulation, letting external code put an object into an inconsistent or invalid internal state by modifying fields directly, bypassing any validation the class's own methods would otherwise perform.
Overusing inheritance for code reuse alone, creating a deep or awkward class hierarchy, when composition (an object containing other objects as fields) would model the actual relationship more naturally and flexibly.
Forgetting to properly initialize all of an object's fields in its constructor, leaving it in a partially valid state immediately after creation.
Confusing a class (the blueprint/definition) with an object/instance (one specific thing created from that blueprint) — a very common vocabulary mix-up for newcomers to OOP.
Modeling a domain's core concepts (users, orders, products in an e-commerce system) as classes whose fields and methods map closely to how those concepts are actually described and used in the business logic.
Using encapsulation to enforce an invariant — for example, ensuring a BankAccount's balance can never become negative by only allowing changes through a controlled withdraw() method that validates the amount first, rather than letting external code set the balance field directly.
Choosing composition over inheritance when a class's relationship to another is more naturally 'has-a' than 'is-a' — for example, a Car having an Engine as a field, rather than Car inheriting from Engine.
Object memory layout An object instance typically stores its own fields' data contiguously (similar to a struct), often alongside some hidden bookkeeping the runtime needs — commonly a pointer or reference to the object's class/type information, used to support dynamic dispatch (calling the correct, possibly overridden, method implementation at runtime) and, in garbage-collected languages, metadata the collector needs to track the object's reachability.
Static (compile-time) vs. dynamic (runtime) dispatch Static dispatch resolves exactly which method implementation to call at compile time, based on the declared (static) type — fast, with no runtime lookup needed. Dynamic dispatch resolves which implementation to call at runtime, based on the object's actual (dynamic) type — enabling polymorphism, but typically requiring an extra indirect lookup (often through a structure like a virtual method table, or 'vtable') at some small runtime cost. This distinction, and its exact mechanisms per language, is developed fully in the future Object-Oriented Programming module.
Garbage collection and object lifetime In garbage-collected languages, an object's memory is automatically reclaimed once the runtime determines nothing can reach it anymore, using strategies like reference counting or tracing garbage collection (covered fully in the future Garbage Collection module) — a fundamentally different lifetime model from a language like C++, where an object's destructor runs deterministically at a point the programmer controls (when it goes out of scope, or is explicitly deleted).
What's the difference between a class and an object?
A class is a blueprint or template defining what fields and methods its instances will have. An object is one specific instance created from that class, with its own copy of the defined fields, though it shares the class's method definitions with every other instance.
What is encapsulation, and why does it matter?
Bundling an object's data together with the methods that operate on it, and restricting direct external access to some of that internal data, so the object's internal consistency (its invariants) can only be changed through controlled, validating methods rather than being set arbitrarily from outside.
What's the difference between inheritance and composition?
Inheritance models an 'is-a' relationship, where a subclass extends and reuses a superclass's fields and methods. Composition models a 'has-a' relationship, where a class contains other objects as fields and delegates to them, rather than inheriting from them directly.
What's the difference between static and dynamic dispatch?
Static dispatch determines which method implementation to call at compile time, based on the declared type, with no runtime overhead. Dynamic dispatch determines it at runtime, based on the object's actual type, enabling polymorphism at the cost of a small runtime lookup, often via a virtual method table.
class Dog:
def __init__(self, name):
self.name = name
def bark(self):
print(self.name + " says woof!")
my_dog = Dog("Rex")
my_dog.bark() # Rex says woof!