Classes Objects: the maker and the made

Classes Objects: the maker and the made

I am sure we all have seen how using just one cookie cutter, a bakery is able to make those cookies in bulk. In fact, all car makers are able to setup their production line for manufacturing numerous units of the same make and model- but it all started with one design!

That is all about classes and objects! haha, well but no lets dive deeper..

Classes and Objects:

They are your blueprints- the cookie cutter, or the car designs. Essentially it describes the what something should look like, the features or attributes, and what is it supposed to do.

Objects are those individual cookies, and the car units finally produced. Each of them draw features, quality, functioning as already described by their class. In programming it is called out as an instance of a class.

Alright, time for us to look at a real world use case- lets take up a smartphone,

class Smartphone:
    def __init__(self, brand, model, screenSize, battery):
        self.brand = brand
        self.model = model
        self.screenSize = screenSize
        self.battery = battery
        self.isPoweredOn = False #smartphone manufactured is powered off by default

    def powerOn(self):
        self.isPoweredOn = True
        return f"{self.brand} {self.model} is now powered on!"

    def powerOff(self):
        self.isPoweredOn = False
        return f"{self.brand} {self.model} is now powered off!"

    def makeCall(self, number):
        if self.isPoweredOn:
            return f"Calling {number}..."
        else:
            return "Phone is powered off, cannot make the call!"

In this example, the class in Smartphone, it is a blueprint of what is to come into reality i.e. the individual phones that we'll use. Notice, the class enables creation of smartphones by allowing us to assign values to attributes or features such as brand, model, screenSize, and battery. Of course we wouldn't want the manufactured phone to be powered on, unless its out from the box and ready for use for consumers, so we have False as value for isPoweredOn.

The blueprint also has listed some abilities, also known as methods that every smartphone will be able to perform i.e. powerOn(), powerOff(), and makeCall()

How do we create the smartphones (individual objects), now that we have the blueprint ready?

# Creating smartphone objects
myPhone = Smartphone("Apple", "iPhone 14", 6.1, 3200)
friendPhone = Smartphone("Samsung", "Galaxy S23", 6.8, 5000)

# Using our smartphones
print(myPhone.powerOn())  # Output: Apple iPhone 14 is now powered on!
print(myPhone.makeCall("555-123-4567"))  # Output: Calling 555-123-4567...
print(friendPhone.brand)  # Output: Samsung

What just happened here?

We created two objects or instances of Smartphone class, each, with its own unique set of characteristics. Yet, both have the same abilities or methods defined within the class.

_ _ init _ _ - the Constructor

This is where the work starts. The first step of clearly defining the attributes of a new instance or object. In the above example the moment we execute myPhone = Smartphone("Apple", "iPhone 14", 6.1, 3200), Python calls the init method, with self referring to the object being created.

It's like saying "take this specific object, and set its brand to Apple, model to iPhone 14, screen size to 6.1 and battery to 3200"

Attributes - Descriptive Characteristics

These as seen are descriptive in nature, defines the feature or characteristics of an object. In our smartphone example, the attributes are brand, model, screenSize, and battery. Now they are of two types actually,

  1. Instance attributes: these are unique to every object, eg. the brand, model etc
  2. Class attributes: common, or shared by all objects or instances of this class Smartphone

Let's add a class attribute for Smartphone objects

class Smartphone:
    # Class attribute - same for all Smartphone objects
    deviceType = "Mobile Communication Device"
    
    def __init__(self, brand, model, screenSize, battery):
        # Instance attributes - unique to each Smartphone object
        self.brand = brand
        self.model = model
        self.screenSize = screen_size
        self.battery = battery
        self.isPoweredOn = False
    # Methods remain the same as before...

Now every smartphone will have the same deviceType as a property

print(myPhone.deviceType)  # Output: Mobile Communication Device
print(friendPhone.deviceType)  # Output: Mobile Communication Device

Methods - Defining Expected Behaviours

after the init method, the methods that we declare, essentially describe the abilities that the object has, and also how it is supposed to behave when made to. In our example, the methods are powerOn(), powerOff(), makeCall().

And like attributes, we can have,

  1. Instance methods: ability of the object to function in a way, eg. powerOn()
  2. Class methods: the class itself is expected to give us some insight
  3. Static methods: neither belongs to the class or the object. but is handy in checking boundaries

Well, it's time to expand the same example:

class Smartphone:
    deviceType = "Mobile Communication Device"
    totalPhonesManufactured = 0  # to track how many phones we've manufactured
    
    def __init__(self, brand, model, screenSize, battery):
        self.brand = brand
        self.model = model
        self.screenSize = screenSize
        self.battery = battery
        self.isPoweredOn = False
        Smartphone.totalPhonesManufactured += 1
    
    # Instance method - acts on a specific phone
    def powerOn(self):
        self.is_powered_on = True
        return f"{self.brand} {self.model} is now powered on!"
    
    # Class method - acts on the class itself
    @classmethod
    def getTotalPhones(cls):
        return f"Total phones manufactured:{cls.totalPhonesManufactured}"
    
    # Static method - doesn't act on a specific phone or the class
    @staticmethod
    def isValidPhoneNumber(number):
        if len(number) != 10 or not number.isdigit():
            return False
        return True

Usage in action:

# creating objects increases our counter
myPhone = Smartphone("Apple", "iPhone 14", 6.1, 3200)
friendPhone = Smartphone("Samsung", "Galaxy S23", 6.8, 5000)

# using class method
print(Smartphone.getTotalPhones())  # Output: Total phones manufactured: 2

# Using static method
print(Smartphone.isValidPhoneNumber("1234567890"))  # Output: True
print(Smartphone.isValidPhoneNumber("123-456-7890"))  # Output: False

We will elaborate on a few more important concepts around classes and objects in our next. Till then have fun learning and observing the concept in real life!