There also are programming languages where you can create objects without (actively) using classes - for example JavaScript. And there are languages where you MUST use classes for pretty much everything (e.g. Java).
Either way, objects allow you to group related data (properties) and functionalities (methods) together. And objects typically expose a public API of methods which can be used anywhere in your code to interact with these objects.
For example:
customer.message(someMessage);
Even though we're technically always dealing with objects, we can differentiate between "real objects" (i.e. used as objects with a public API) and mere data containers (or data structures, though that term is also used in different ways).
A data container is really just that - an object which holds a bunch of data. Here's an example:
class UserData:
def __init__(self):
self.name = ""
self.age = 0
# Create an instance of UserData
user_data = UserData()
user_data.name = 'Max'
user_data.age = 31
This class has no methods and both properties are exposed publicly. An object on the other hand hides it's data from the public and instead exposes a public
API in the form of methods:
class User:
def __init__(self, name, age):
self.name = name
self.age = age
def greet(self):
print(f"Hi! I'm {self.name} and I'm {self.age} years old.")
# Create an instance of User
user_data = User('Max', 31)
user_data.greet()
Both are absolutely valid types of objects - it's just important to use the right kind of object for the right job. And you should avoid mixing the types.
Why does this matter?
When writing clean code, we shouldn't try to access some internals of an object. This bares the danger of the object changing these internals and our code breaking because of that.
In addition, it makes code harder to read, if we have to interpret the meaning and values of properties of other classes.
Calling something like greet() on the other hand is straightforward.
Polymorphism is a fancy term but in the end it just means that you re-use code (e.g. call the same method) multiple times but that the code will do different things, depending on the object type.