Objects


Python.

Object-oriented Programming

Python supports a particular form of programming called Object-oriented programming (OOP). In OOP, you can create objects that represent things and define what they do using methods (functions attached to objects). This sounds very vague, and that's because an object can represent pretty much anything.

For example, you can make a Car object with methods like start, stop, and go. Similarly, you can make a Human object with methods like eat, sleep, and walk.

Object-Oriented Programming allows you to model real-world entities and their behavior in your code, making it easier to organize and manage complex programs.

In this module, you will learn the basics of creating objects in Python!


Challenges

Object Creation

Creating an object in Python is simple. You define a class using the class keyword. A class acts as a blueprint for creating objects. You can give an object specific attributes (variables) and methods (functions) that define its behavior.

Here’s an example of a basic class:

class MyClass:
    def __init__(self):
        self.my_attribute = 5
 
    def my_method(self):
        print(self.my_attribute)

Let's break it down:

  • class MyClass defines a new class called MyClass. The class name can be anything you like.

  • __init__(self) is a special method that runs when you create an instance of the class, which is known as an object. It sets up the object's initial state.

  • self refers to the specific instance of the class. You use it to store and access attributes and methods tied to that instance.

  • my_method(self) is a method (essentially a function) attached to the class. It can access the object's attributes using self.

Challenge:

Create a Car class.

Give it a fuel attribute of 50.

Add a go method that subtracts 1 from the fuel attribute each time it's called.

👉 Run /challenge/verify <your_python_file> to check your solution!

Instances

So, you learned how to write a class. That's great! But how do you actually use them?

This is where the terminology of instances comes in. When you write a class, you have just written the underlying logic of how an object can function, you haven't actually created that object. You need to instantiate it, or create an instance of your class.

Let's say you have the following Employee class, and they're allowed to clock in and clock out. They also have various attributes.

class Employee:

    def __init__(self):
        self.employee_id = 34
        self.title = "Programmer"
        self.salary = 90000
        self.working = False

    def clock_in(self):
        self.working = True

    def clock_out(self):
        self.working = False

How do we make an instance of the employee class and actually use the code? It's simple!

employee1 = Employee()
employee2 = Employee()
employee3 = Employee()

In the code above, we created THREE different instances of the employee class. This means we now have three Employee objects that we can use in our code.

If we want to utilize the methods or attributes in our class we can invoke them like this:

employee1.check_in()

employee2.check_out()

print(employee3.title)

Here, you can see that even though the check_in and check_out methods have the parameter self in our class code, we don't actually pass anything into the method when we call it. This is because self just tells the method to reference the instance it belongs to. This gives the method access to everything inside the object.

To complete this challenge and get a flag you must:

  1. Create a class called Dog.
  2. Give it an attribute called is_sitting and set it to False by default.
  3. Create a method called sit that sets the attribute is_sitting to True.
  4. Create an instance of your Dog class and call the sit method.
  5. Print out the is_sitting attribute of your Dog instance to make sure it says True after calling sit.

After you have written that, run /challenge/verify <your_python_file> to verify your code and receive the flag!

Arguments

In the past two challenges, you have learned how to create classes, and then use those classes as objects. Since objects are meant to reflect real life "things" there needs to be some customization. Going back to our Car class from the first challenge, not EVERY vehicle will have the same fuel count, color, make, model, etc. We could just create different classes for every different combination of these things, but that defeats the whole purpose of a class! Classes are supposed to be basic models of real life things that we can build upon!

One thing that allows us to build upon our basic classes are arguments. Arguments are passed to a class when it is being instantiated for the purpose of specifying particular attributes that our unique to our particular instance. Let's use the car as an example.


class Car:

    def __init__(self):
        self.color = "Black"
        self.make = "Dodge"
        self.model = "Viper"
        self.year = 2017
        self.spoiler = None
        self.started = False
        self.driving = False

    def start(self):
        if not self.started:
            self.started = True

    def go(self):
        if self.started and not self.driving:
            self.driving = True

    def stop(self):
        if self.started and self.driving:
            self.driving = False

This is a bigger version of our Car class. You can see there are many attributes here. Many of them are car agnostic (they are the same for all cars), but a few are not. This class really only works well for representing a Black 2017 Dodge Viper. However, we can rewrite this class so that we can make any car we want. Any make, model, color, and year. Let's see how.


class Car:

    def __init__(self, make, model, year, color):
        self.color = color
        self.make = make
        self.model = model
        self.year = year
        self.spoiler = None
        self.started = False
        self.driving = False

    def start(self):
        if not self.started:
            self.started = True

    def go(self):
        if self.started and not self.driving:
            self.driving = True

    def stop(self):
        if self.started and self.driving:
            self.driving = False

You'll notice the changes were made to our __init__ function.

  1. Our __init__ function now has more paramters than just self. Our initialization function now takes in make, model, year, and color. This is how we will pass in that specific infomration.
  2. Within __init__ we are setting our class attributes to the new parameters we are passing to our init function. self.color = color, self.make = make, etc. It is good convention to name the paramters to our __init__ function the same as the class attributes we are creating.

Now this class can be used to represent ANY vehicle we want! But how do we do that? We can specify these particular variables when we are creation instances of our cars! Here are a couple examples of how we may create a couple unique vehicles using the same Car class.


viper = Car("Dodge", "Viper", 2017, "Black")
tesla = Car("Tesla", "Model S", 2023, "Gray")

viper.start()
viper.go()
viper.stop()

tesla.start()
tesla.go()
tesla.stop()

In the above code, we used our very basic car class to create TWO unqiue car objects that have different attributes that we assigned when we instantiated our Car class. This allows our classes to remain barebones, with a lot of customization!

For this challenge:

  1. Create a Student class.
  2. Give the Student class customizable attributes for their name, age, and gender.
  3. Create two unique instances of the Student class. NOTE: You don't need to create any methods for this student class.

Run `/challenge/verify <your_python_file> to verify your code and receive the flag.

Knowledge Check I

Now that you have a grasp of the basics, let's try and tie them together!

  1. Create a Fish class.
  2. Give it the following attributes:
    • color
    • length
    • type (Walleye, Bass, etc.)
    • is_swimming (set it to False by default)
    • is_eating (set it to False by default)
  3. Program the following methods:
    • swim (Set is_swimming to True, and is_eating to False)
    • eat (Set is_eating to True, and is_swimming to False)
  4. Create two unique instances of the Fish class and run swim and eat on both.

Once you are done, run /challenge/verify <your_python_file> to verify your code and receive the flag!

Sub-classes

Now that you have a basic grasp of classes, we will look at a more advanced technique used in Object-Oriented Programming in Python.

Let me pose a common problem you may encounter. Let's say you want to create seeral different animal classes. You may have a pig, a horse, and a donkey. These three animals are distinct in many ways, and similar in others. It makes sense to separate them.

However, they all also perform a lot of the same tasks. They all eat, sleep, and walk. If you created three classes: one for Pig, one for Horse, and one for Donkey you would also have to write the eat, sleep, and walk methods for each of the classes, even though they are the same thing.

To get around this, we can use something called sub-classes! A sub-class is a class that derives methods and attributes from a parent class, but then adds its own functionality when necessary!

How does this help with our above example? I'll show you!

You can start by creating an Animal class like this:

class Animal:

	def __init__(self, color):
		self.color = color
		self.is_walking = False
		self.is_eating = False
		self.is_sleeping = False

	def walk(self):
		self.is_walking = True
		self.is_eating = False
		self.is_sleeping = False

	def eat(self):
		self.is_walking = False
		self.is_eating = True
		self.is_sleeping = False

	def sleep(self):
		self.is_walking = False
		self.is_eating = False
		self.is_sleeping = True

You can see in the above class it has the attributes necessary to denote if an animal is walking, sleeping, or eating. It also has the methods necessary to perform those tasks! This is a very generic Animal class that we can now create subclasses from!

Let me show you what creating a Donkey subclass looks like!

class Donkey(Animal):

	def __init__(self, color, name):
		super().__init__(color)
		self.name = name
		self.color = color
		self.is_carrying = False

	def carry(self):
		self.is_carrying = True

In the definition to our sub-class, you may notice a couple new things!

  1. In our class definition, we have added parenthesis and put our parent class inside it. This tells the Donkey class to inherit from the Animal class.
  2. In our __init__ method for our Donkey class, we call super().__init__(). All this is doing is running the __init__ function from the Animal class within the __init__ function of our Donkey class. This initializes it with the attributes and methods of our parent Animal class!

Note, also, that the Animal class has a color attribute we can pass to it. Our Donkey class utilizes that same field, but we pass it into super().__init__() which will initialize the color attribute for us.

I also added a new attribute to donkey called name. This doesn't get passed to super().__init__() because it doesn't exist in the Animal class.

Now that we have written the Donkey class, inheriting from the Animal class, we should be able to use Donkey like this:

d = Donkey("Gray")
d.eat()
d.walk()
d.carry()
d.sleep()

Notice how I didn't have to write the eat, walk, or sleep methods for the Donkey class! I only had to write them once! Now, any animal sub-class that I create using the Animal parent class will all have the attributes and methods associted with the Animal class.

This makes objects very customizable, and versatile. You can create very generic classes, and then expand them through sub-classes that have more specific functionality while retaining the original functionality of the parent class!

For this challenge, I will give you an Employee class, and you have to create a sub-class using the Employee class.

class Employee:
    def __init__(self, name, employee_id, salary):
        self.name = name
        self.employee_id = employee_id
        self.salary = salary

    def display_info(self):
        print(f"Name: {self.name}, ID: {self.employee_id}, Salary: ${self.salary}")
  1. Create a sub-class called Doctor.
  2. Give him a customizble attribute of specialty
    • It will look something like this: def __init__(self, name, employee_id, salary, specialty). This specialty will be something like: Cardiologist, Pediatrician, Surgeon, etc.
  3. Create a diagnose method that takes in a patients name, and a diagnosis and then prints out " is diagonsed with ."

To verify your code and get the flag, run /challenge/verify <your_python_file>


30-Day Scoreboard:

This scoreboard reflects solves for challenges in this module after the module launched in this dojo.

Rank Hacker Badges Score