Object-Oriented Programming (OOP) with Copilot
When learning Python, you’ll often hear about Object-Oriented Programming (OOP). OOP is a way of organizing your code using "objects," which bundle together data and behavior.
You can think of it like creating your own "custom types" (called classes) and making "real-world" versions of them (called objects).
In this lesson, we’ll explore classes, constructors, inheritance, encapsulation, and method overriding — all using Copilot prompts.
Classes and Objects
A class is a blueprint for creating objects. Each object (also called an instance) is created from that class and can hold different data.
Prompt:
1
# Write a Python class for a basic calculator with add, subtract, multiply, and divide methods
Copilot might suggest:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
class Calculator: def add(self, a, b): return a + b def subtract(self, a, b): return a - b def multiply(self, a, b): return a * b def divide(self, a, b): if b != 0: return a / b else: return "Cannot divide by zero"
Explanation
class Calculator:
defines a new class named Calculator.- Each method (add, subtract, multiply, divide) performs a specific calculation.
- The
self
parameter refers to the instance of the class (the object calling the method).
Example Usage
1 2 3
calc = Calculator() print(calc.add(10, 5)) # Output: 15 print(calc.divide(10, 0)) # Output: Cannot divide by zero
You first create an object (calc = Calculator()
) and then call its methods.
Constructors (
A constructor is a special method named __init__
. It automatically runs when you create a new object. You use it to set up initial values (attributes).
Prompt:
1
# Create a class Car with attributes like make, model, and year
Copilot might suggest:
1 2 3 4 5 6 7 8
class Car: def __init__(self, make, model, year): self.make = make self.model = model self.year = year def display_info(self): return f"{self.year} {self.make} {self.model}"
Explanation
__init__(self, make, model, year)
: Called when a new Car is created.self.make = make
saves the passed value as an attribute you can access later.- The method
display_info()
returns a formatted string with the car's details.
Example Usage
1 2
my_car = Car("Toyota", "Corolla", 2020) print(my_car.display_info()) # Output: 2020 Toyota Corolla
You pass the details when creating the object, and they’re saved inside the object.
Inheritance
Inheritance allows you to create a new class based on an existing class. The new class (child) inherits the parent class's attributes and methods, but can also add or change things.
Prompt:
1
# Write a parent class Animal and a child class Dog that inherits from Animal
Copilot might suggest:
1 2 3 4 5 6 7 8 9 10
class Animal: def __init__(self, name): self.name = name def speak(self): return "Some generic sound" class Dog(Animal): def speak(self): return "Woof!"
Explanation
class Animal
: Parent class.__init__
sets the name of the animal.speak()
in Animal returns a generic sound.class Dog(Animal)
: Child class that inherits from Animal.Dog
overridesspeak()
to return "Woof!"
Example Usage
1 2 3 4 5
animal = Animal("Generic Animal") dog = Dog("Buddy") print(animal.speak()) # Output: Some generic sound print(dog.speak()) # Output: Woof!
The child class Dog
has the same initialization as Animal
, but a different speak()
behavior.
Encapsulation and Private Members
Encapsulation means keeping certain data inside a class private so it cannot be changed or accessed directly from outside. In Python, we use double underscores (__
) to make attributes private.
Prompt:
1
# Show an example of private variables in a Python class
Copilot might suggest:
1 2 3 4 5 6 7 8 9 10 11
class Person: def __init__(self, name, age): self.name = name self.__age = age # private variable def get_age(self): return self.__age def set_age(self, new_age): if new_age > 0: self.__age = new_age
Explanation
__age
: Private variable. Cannot be accessed directly (e.g.,p.__age
will cause an error).get_age()
allows you to read__age
.set_age()
allows you to update__age
safely.
Example Usage
1 2 3 4 5 6 7 8
p = Person("Alice", 30) print(p.name) # Output: Alice print(p.get_age()) # Output: 30 p.set_age(35) print(p.get_age()) # Output: 35 # print(p.__age) # This will cause an error
Encapsulation helps protect your data from accidental changes.
Method Overriding
When a child class has a method with the same name as a parent class, it overrides (replaces) that method. This allows custom behavior for the child class.
Prompt:
1
# Demonstrate method overriding in child classes
Copilot might suggest:
1 2 3 4 5 6 7
class Vehicle: def start(self): return "Starting vehicle" class Bike(Vehicle): def start(self): return "Starting bike with a kick"
Explanation
Vehicle
has astart()
method.Bike
inherits fromVehicle
but defines its ownstart()
method, overriding the original.
Example Usage
1 2 3 4 5
v = Vehicle() b = Bike() print(v.start()) # Output: Starting vehicle print(b.start()) # Output: Starting bike with a kick
Key Takeaways
- Use classes to group data and methods together.
- The
__init__
constructor initializes objects with data when they are created. - Inheritance allows you to build new classes from existing ones, reusing code.
- Encapsulation hides important data to prevent unintended access.
- Method overriding lets child classes change inherited behavior.
Practice Challenge
Prompt:
1
# Create a parent class Shape with a method area. Then create a child class Circle that overrides area to calculate π * r^2.
Try creating the classes with Copilot. Create a Circle object with a specific radius and print its area.
Mini Exercises
- Create a class
Book
with attributes title and author. Add a methoddisplay()
to print book details. - Create a child class
EBook
that inherits fromBook
and adds an attributefile_size
. Overridedisplay()
to also show the file size. - Create an object of
EBook
and calldisplay()
.
Extra Tips
- Always understand what Copilot suggests before accepting it.
- Change attribute names and test with different data.
- Practice calling methods and accessing attributes directly.