Python OOP VOL 2 (codedexters ETR)
Python OOP VOL 2 (codedexters ETR)
Let us now update the Dog class that we created with an .__init__() method that
creates .name and .age attributes:
Python
# dog.py (((Name of your file)))
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
Make sure that you indent the .__init__() method’s signature by four spaces, and the body of
the method by eight spaces (that’s for anything that falls under the def __init__). This indentation
is vitally important. It tells Python that the .__init__() method belongs to the Dog class.
In the body of .__init__(), there are two statements using the self variable:
1. self.name = name creates an attribute called name and assigns the value of
the name parameter to it.
2. self.age = age creates an attribute called age and assigns the value of
the age parameter to it.
Attributes created in .__init__() are called instance attributes. An instance attribute’s value
is specific to a particular instance of the class. All Dog objects have a name and an age, but the
values for the name and age attributes will vary depending on the Dog instance.
On the other hand, class attributes are attributes that have the same value for all class instances.
You can define a class attribute by assigning a value to a variable name outside
of .__init__().
For example, the following Dog class has a class attribute called species with the value
"Canis familiaris":
Python
# dog.py
class Dog:
species = "Canis familiaris"
Use class attributes to define properties that should have the same value for every class instance.
Use instance attributes for properties that vary from one instance to another.
Now that you have a Dog class, it’s time to create some dogs!
Python
>>> class Dog:
... pass
...
>>> Dog()
<__main__.Dog object at 0x106702d30>
You first create a new Dog class with no attributes or methods, and then you instantiate
the Dog class to create a Dog object.
In the output above, you can see that you now have a new Dog object at 0x106702d30. This
funny-looking string of letters and numbers is a memory address that indicates where Python
stores the Dog object in your computer’s memory. Note that the address on your screen will be
different.
Now instantiate the Dog class a second time to create another Dog object:
Python
>>> Dog()
<__main__.Dog object at 0x0004ccc90>
The new Dog instance is located at a different memory address. That’s because it’s an entirely
new instance and is completely unique from the first Dog object that you created.
Python
>>> a = Dog()
>>> b = Dog()
>>> a == b
False
In this code, you create two new Dog objects and assign them to the variables a and b. When you
compare a and b using the == operator, the result is False. Even though a and b are both
instances of the Dog class, they represent two distinct objects in memory.
Now create a new Dog class with a class attribute called .species and two instance attributes
called .name and .age:
Python
>>> class Dog:
... species = "Canis familiaris"
... def __init__(self, name, age):
... self.name = name
... self.age = age
...
To instantiate this Dog class, you need to provide values for name and age. If you don’t, then
Python raises a TypeError:
Python
>>> Dog()
Traceback (most recent call last):
...
TypeError: __init__() missing 2 required positional arguments: 'name' and
'age'
To pass arguments to the name and age parameters, put values into the parentheses after the
class name:
Python
>>> miles = Dog("Miles", 4)
>>> buddy = Dog("Buddy", 9)
This creates two new Dog instances—one for a four-year-old dog named Miles and one for a
nine-year-old dog named Buddy.
The Dog class’s .__init__() method has three parameters, so why are you only passing two
arguments to it in the example?
When you instantiate the Dog class, Python creates a new instance of Dog and passes it to the
first parameter of .__init__(). This essentially removes the self parameter, so you only
need to worry about the name and age parameters.
Note: Behind the scenes, Python both creates and initializes a new object when you use this
syntax. If you want to dive deeper, then you can read the dedicated tutorial about the Python
class constructor.
After you create the Dog instances, you can access their instance attributes using dot notation:
Python
>>> miles.name
'Miles'
>>> miles.age
4
>>> buddy.name
'Buddy'
>>> buddy.age
9
You can access class attributes the same way:
Python
>>> buddy.species
'Canis familiaris'
One of the biggest advantages of using classes to organize data is that instances are guaranteed to
have the attributes you expect. All Dog instances have .species, .name, and .age attributes,
so you can use those attributes with confidence, knowing that they’ll always return a value.
Although the attributes are guaranteed to exist, their values can change dynamically:
Python
>>> buddy.age = 10
>>> buddy.age
10
The key takeaway here is that custom objects are mutable by default. An object is mutable if you
can alter it dynamically. For example, lists and dictionaries are mutable, but strings and tuples
are immutable.