Recommended
Python OOP — Timed Test (3 questions)
No account needed. Answers and explanations arrive when you submit.
What this topic tests
The mix every Python OOP set is built to, and the questions published against it so far. Nothing here is hidden before you start.
| Level | Target share | Published |
|---|---|---|
| Easy | 40% | 1 |
| Medium | 40% | 2 |
| Hard | 20% | 0 |
| Total | 3 |
Python OOP — the theory
Object-oriented programming (OOP) is a programming paradigm built around organizing code into objects that bundle together data and the behavior that operates on that data, and Python supports this paradigm fully.
Classes and objects. A class is a blueprint for creating objects, defined using the class keyword. It specifies what data (attributes) and behavior (methods) instances of that class will have. An object, or instance, is a specific realization of a class — if Car is a class, a particular car with a specific color and model is an instance of that class. Classes let you model real-world or conceptual entities in code in a structured, reusable way.
Attributes and methods. Attributes are the data associated with an object (for example, a Car object might have color and model attributes), while methods are functions defined within a class that operate on that object's data (for example, a start_engine() method). Python conventionally uses self as the first parameter of instance methods, referring to the specific instance the method is being called on.
The `__init__` method. Python classes typically define an __init__ method, called automatically when a new instance is created, used to set up the object's initial attributes. This is Python's version of what other languages often call a constructor.
Inheritance. Inheritance allows a new class to be based on an existing class, automatically gaining its attributes and methods while being able to add new ones or override existing behavior. This supports code reuse and lets you model natural hierarchies — for example, a SportsCar class could inherit from a general Car class, gaining everything a car has while adding sports-car-specific behavior. The class being inherited from is often called the parent or base class, and the new class is the child or derived class.
Encapsulation. Encapsulation refers to bundling data and the methods that operate on it together within an object, and controlling how that data can be accessed or modified from outside the object. While Python doesn't enforce strict access restrictions the way some languages do, it uses naming conventions (like a leading underscore) to signal that certain attributes are intended for internal use rather than direct external access.
Polymorphism. Polymorphism refers to the ability for different classes to be used interchangeably if they share a common interface — for example, if multiple classes each define a make_sound() method, code that calls make_sound() on an object doesn't need to know the object's specific class, only that it supports that method. This allows for flexible, extensible code that can work with many different object types through a shared, predictable interface.
When OOP helps versus when it adds unnecessary complexity. OOP tends to help most when a problem naturally involves modeling distinct entities with their own data and behavior, and when code reuse through inheritance or shared interfaces genuinely simplifies the design. For simpler scripts or tasks that don't naturally decompose into distinct interacting objects, a more straightforward, function-based approach can sometimes be clearer than forcing an object-oriented structure onto a problem that doesn't need it.
Class attributes versus instance attributes. Attributes set inside __init__ on self belong to each individual instance — every Car gets its own color. Attributes defined directly on the class body are shared by all instances — useful for constants or defaults common to the whole class, like a wheels = 4 every car shares. Confusing the two is a classic mistake, particularly with mutable class attributes: a list defined at class level is one list shared by every instance, which is rarely what a beginner intended.
Special methods. Python classes can define specially named methods — written with double underscores, like __str__ or __len__ — that hook into the language's built-in behavior: defining __str__ controls what printing an object shows, and defining __len__ lets len() work on your objects. These "dunder" methods are how user-defined classes participate in Python's built-in operations as naturally as the built-in types do, and recognizing them demystifies a great deal of Python code that otherwise looks like magic.
Composition as an alternative to inheritance. Inheritance is not the only way to build classes out of other classes. Composition — giving an object another object as an attribute, a Car that has an Engine rather than being one — is often the more flexible design, because it models a "has-a" relationship rather than forcing an "is-a" hierarchy. Deep inheritance chains grow brittle as designs evolve; experienced Python programmers commonly reach for composition first and reserve inheritance for genuine hierarchies where the child truly is a specialized version of the parent.
Understanding these core OOP concepts — classes, objects, inheritance, encapsulation, and polymorphism — provides a foundation not just for Python specifically, but for object-oriented design as it appears across many other programming languages as well: the vocabulary transfers almost unchanged, even where the syntax differs.
Sample questions
Three questions from this topic, with the answer and the reasoning shown.
Q1EasyWhat is a class in Python?
- A blueprint for creating objects, defining their attributes and behaviorCorrect
- A built-in Python function for printing text
- A type of loop
- A file extension unique to Python
Explanation
A class is the template; the objects you make from it are the instances, and keeping those two apart is most of what this question is worth. The tutorial puts it plainly: "Classes provide a means of bundling data and functionality together. Creating a new class creates a new type of object, allowing new instances of that type to be made." The glossary is shorter still, calling a class "A template for creating user-defined objects."
Then there is the bug that catches almost everyone once. A name you assign directly in the class body belongs to the class, not to each object: "instance variables are for data unique to each instance and class variables are for attributes and methods shared by all instances of the class". Put a mutable list up there and every instance appends to the same list. Anything that should differ per object gets attached to self inside the initialiser instead.
The three wrong answers share a shape — a class mistaken for some other Python thing you met earlier. Printing is a function, looping is a statement, and Python files end in .py.
Q2MediumWhat does inheritance allow in object-oriented Python?
- A new class can be based on an existing class, gaining its attributes and methodsCorrect
- Classes can never share any behavior
- Only one class can exist per Python file
- Objects lose all their data once created
Explanation
Inheritance is a lookup rule before anything else. Base a new class on an existing one and Python remembers the parent: "if a requested attribute is not found in the class, the search proceeds to look in the base class. This rule is applied recursively if the base class itself is derived from some other class." That is the payoff: methods you never wrote are found by walking upward, so shared behaviour lives in one place and each subclass carries only its differences.
The other half is that you may disagree with the parent — "Derived classes may override methods of their base classes." Define one of the same name on the subclass and yours wins the search. Usually you want to extend the parent, not discard it: "An overriding method in a derived class may in fact want to extend rather than simply replace the base class method of the same name." That is what a super() call in your override buys you; omitting it from an initialiser is the classic half-built subclass.
The wrong options deny sharing, invent a one-class-per-file rule, or describe data loss Python never does.
Q3MediumWhat is the purpose of the `__init__` method in a Python class?
- It's called automatically when a new instance is created, to set up initial attributesCorrect
- It permanently deletes an object
- It runs only when a program ends
- It is required only for built-in Python types
Explanation
The word people reach for here is constructor, and that habit is what this question should break. The initialiser does not build your object; it is handed one that already exists and given the chance to furnish it. The data model is precise about the ordering: it is "Called after the instance has been created (by __new__()), but before it is returned to the caller." The tutorial agrees: "When a class defines an __init__() method, class instantiation automatically invokes __init__() for the newly created class instance."
Two consequences follow. It must not hand a value back, because substituting or reusing an object is the job of __new__, not of the initialiser. And its default arguments are evaluated once, when the function is defined: "The default value is evaluated only once. This makes a difference when the default is a mutable object such as a list, dictionary, or instances of most classes." So a default of an empty list is shared by every instance ever created; pass None and build it in the body.
The distractors describe a destructor, a shutdown hook, and a rule about built-ins. None runs at instantiation.
Practise all 3 questions
Every published question in Python OOP, with its answer and explanation.