Python Programming · Foundations

Object-Oriented Programming

Want it in plain words first? Jump to Eli explains — the same idea, no jargon.
On this page 9 sections
  1. In 30 seconds
  2. Why this matters
  3. The college version
  4. Eli explains
  5. Worked example
  6. Key takeaway
  7. Quick check
  8. Study tools
  9. Sources & references

In 30 seconds

Object-oriented programming (OOP) is a way to organize a program around objects: values with a , , and operations. Rather than scattering facts and the code that acts on them, a design can give related responsibilities a home. In Python, OOP is a useful tool, not a requirement: small programs can be clearer with simple functions and data.

Why this matters

OOP gives students a vocabulary for deciding where belongs as a program grows. It can make a model of a library account, game character, or sensor easier to extend because related data and operations travel together. The important skill is not naming four “pillars”; it is choosing a design that makes responsibilities, dependencies, and changes understandable. That judgment transfers to later work with APIs, testing, and larger codebases.

The college version

Objects and responsibilities

Object-oriented programming is a design approach: organize some parts of a program around objects and the operations that make sense for them. In Python’s data model, every has an identity, a type, and a value. The type helps determine the operations that object supports. This is a precise foundation for OOP: an object is not merely a bag of variables, and OOP is not synonymous with the class keyword. A program already works with objects when it works with strings, lists, functions, and user-defined values.

When designing an application, state is information an object is responsible for, while behavior is an operation it can perform or support. A LibraryAccount might be responsible for a borrower’s current loans and for requesting a renewal. Keeping those ideas together can reduce the number of places a future change must be made. It does not mean every noun in a problem statement deserves its own object. Good boundaries come from responsibilities that change together, not from a ritual of converting every noun into a class.

Python classes are one way to define a new type and make instances of that type. The next lesson, Classes and Objects, owns the declaration syntax, attributes, constructors, and instance mechanics. This lesson stays at the design level: before writing a class, decide what an object should know, what it should do, and which details other code actually needs.

Encapsulation is an interface decision

means grouping related state and behavior and exposing a usable interface instead of asking unrelated code to manipulate every internal detail. For example, code that wants to renew a library item should ask an account to attempt a renewal; it should not have to know every rule used to decide eligibility. That leaves room to change the internal rule while preserving the operation clients use.

Encapsulation is often described as “hiding data,” but that shorthand can mislead Python learners. Python does not turn a leading underscore into a hard private-access wall. A name such as _loans communicates an internal-use convention; it does not prevent access. The real benefit is architectural: callers depend on a small, intentional interface, and the implementation can be revised coherently. Encapsulation therefore includes clear names, focused methods, and avoiding needless exposure—not merely punctuation in an attribute name.

It also has limits. A tiny script may be less clear if it introduces a wrapper object around one value with no meaningful behavior. Encapsulation is useful when it protects an invariant, centralizes a rule, or gives a concept a stable responsibility. It is not an automatic upgrade for every variable.

Inheritance, polymorphism, and composition

describes a relationship in which a derived type receives attributes and methods from a base type and may add or replace behavior. It can fit a genuine “is a” relationship. If every ElectricBike should be usable wherever a Vehicle is expected, shared vehicle behavior might belong in a base design. But inheritance also creates a dependency: changes to the base design can affect derived types. It is not a convenient way to reuse a few lines of code.

is the ability to use a common operation with values of different types, while each type supplies behavior suitable to itself. In Python, the useful question is often “does this object support the operation I need?” A reporting function may call summary() on different objects without needing a long chain of type tests. Some polymorphism arises through inheritance; Python can also use a shared method-shaped interface without a shared base class. The caller relies on behavior, not on a particular concrete type.

is another common option: one object has or uses another object. A Car has an Engine; it is not an Engine. Composition usually makes the dependency explicit and lets components vary independently. A practical design sequence is: identify responsibilities, define the smallest useful interface, use composition for “has a” relationships, and choose inheritance only when substitutability and shared behavior are genuinely stable. OOP is thus a collection of trade-offs, not a template that every Python program must follow.

Eli, the EliExplains learning guide

Eli explains

The same idea, in plain words

Explain it like I’m 10

Think of an object as a well-labeled station at a workshop. The station keeps the tools and information needed for one job together, and it offers a few clear actions such as “measure” or “cut.” Other people do not need to rearrange every drawer to ask for a cut; they use the station’s controls. OOP helps choose these stations and their responsibilities.

Inheritance is like making a specialized station from a general station: it may keep the general controls and add a new one. Polymorphism means someone can press the same labeled control on different stations and get the appropriate result. Composition is different: a station may use another station as a component rather than pretending to be that station.

Picture it like this

A workshop with stations and clearly labeled controls.

Where the picture stops working

Programs do not have physical drawers, and Python’s access conventions are not locked doors. Real designs can share behavior without inheritance, and an object’s boundaries are choices made by programmers.

Worked example

Suppose a transit app must show a short status for a bus and a train. Both can provide status(), but the bus reports its route while the train reports its line and platform. A display routine can ask each item for status() and show the returned text; it does not need to know which concrete type it received. That is polymorphism at the design level. If a bus uses a separate Location value to track coordinates, that is composition: the bus has a location, rather than being a location. Do not create a base class merely because two examples share one method name; use one only when the shared contract and substitutability are valuable.

Key takeaway

OOP organizes responsibilities around objects and interfaces. Use encapsulation, inheritance, polymorphism, and composition as design tools chosen for a problem—not as boxes every Python program must check.

Quick check

3 questions here, of 5 in this lesson’s practice set. Answers stay hidden until you check.

Question 1 of 3foundational

In Python’s data model, which set describes every object?

Choose an answer, then check it.
Question 2 of 3intermediate

A program lets callers request account.renew(item) without editing the account’s loan list directly. Which design idea does this best illustrate?

Choose an answer, then check it.
Question 3 of 3intermediate

Which relationship is usually best expressed with composition rather than inheritance?

Choose an answer, then check it.
Practice all 5

Keep learning

Ready to build on this? Continue to the next lesson.

Practice this lesson
Study tools & related lessonsYou’ll learn to · Common mistakes · Easily confused · Key vocabulary · Related

You’ll learn to

  • Define object-oriented programming as an organizational approach.
  • Distinguish an object’s state from its behavior.
  • Explain encapsulation, inheritance, and polymorphism without treating them as mandatory rules.
  • Apply composition versus inheritance to a small design decision.
  • Analyze why a common operation can work across different object types.

Common mistakes

  • Equating OOP with writing many classes.

    Start with responsibilities; functions and plain data may be clearer for a small task.

  • Calling every code-reuse opportunity inheritance.

    Consider composition or a helper function; inheritance models a stable substitutable relationship.

  • Treating _name as enforced private access in Python.

    It is a convention; encapsulation comes from an intentional interface and design.

  • Assuming polymorphism requires a shared parent class.

    In Python, objects can support the same needed operation without inheriting from one custom base.

Easily confused

Inheritance vs. Composition

Inheritance models a derived type based on a base type; composition models one object using or containing another.

Encapsulation vs. Access control

Encapsulation is an interface and responsibility design; Python naming conventions alone do not enforce privacy.

Polymorphism vs. Type checking chain

Polymorphism asks objects for a common operation; a type-checking chain selects behavior externally.

Key vocabulary

object
A runtime value with an identity, type, and value in Python.
type
A classification that determines an object’s supported operations and possible values.
state
Information for which an object is responsible at a particular time.
behavior
An operation an object can perform or support.
encapsulation
Organizing related state and behavior behind a deliberate interface.
inheritance
A relationship in which a derived type obtains behavior or attributes from a base type.
polymorphism
Using a common operation with values whose types can provide different appropriate behavior.
composition
Building a design in which one object uses or contains another object.

Sources & references

  1. The Python Language Reference — Data model — Python Software Foundation
  2. The Python Tutorial — 9.2 Python Scopes and Namespaces — Python Software Foundation

EliExplains lessons are original prose written from the open, credible references above. See Copyright & Licensing.

Researched 2026-08-19

Educational content only. It is not medical, legal or professional advice. Found an error? Tell us.