Now that we've seen how we can create a new class.
Even if it's a class with nothing inside.
And we've seen how we can create a new object from that class
by using the same code that we used in yesterday's lessons.
The next question is: "Well, how do we create an attribute for that class?". Well,
one of the easiest ways of doing this is simply tapping into your object and
then adding an attribute.
So we could say user_1.id =
"001".
And we could add as many attributes as we want just by using this method of
using the dot notation after the name of the object,
and then just adding any piece of data we want. So now,
if I go ahead and print user_1.username,
you'll see that this attribute now exists in this object
[Inaudible]
And you can see the value that's held in that attribute being printed in the
console. So just a quick reminder,
an attribute is a variable that's associated with an object.
So it's almost as if we just created a new variable, but in this case,
we've attached it to an object. But here's a question though,
if we had lots and lots of attributes like this,
and every single time we create a new user,
let's say we created user_2 and we had to do the same thing,
create it from the class and then say,
user_2.id = "002",
and user_2.username
= "jack". And this is one,
a little bit prone to error because it's perfectly valid for me to make a typo
or change the name of an attribute where I end up with something like this.
So is there a way of making this simpler?
How can I specify all these starting pieces of information
when I create my object from the class? Now,
in order to do this, we have to understand something called a constructor,
which is a part of the blueprint that allows us to specify what should happen
when our object is being constructed.
And this is also known in programming as initializing
an object. When the object is being initialized,
we can set variables or counters to they're starting values. In Python,
the way that we would create the constructor is by using a special function,
which is the init function.
And you can tell it's special because it isn't just the Def keyword
and then the name of the function. It's got two underscores
either side of the name.
And this means that it's a method that the Python interpreter knows about and
knows that it has a special function. Now,
what is the special function? Well, it's normally used to initialize the attributes.
So if inside our class
we add this init function and you can see as soon as I write def and then
init, I've really got autofill helping me so I can just hit enter
once it's selected. Now,
inside this init function is where we initialize or create the starting
values for our attributes. Now,
the important thing to remember is that the init function is going to be called
every time you create a new object from this class.
For example, if I print,
then every time that this construction happens
when we create a new user,
then this print statement is going to be triggered.
So you can see here, this print statement gets triggered
and then we print the user_1's username, and then we've got
another user being created. Just as a quick reminder,
the attributes are the things that the object will have.
And they are basically just variables that are associated with the final
object. So for example, if you're constructing a car bject,
then one of those attributes could be the number of seats it has and
normally that's equal to five.
So how do we set these attributes in the constructor? Well,
this is what the code would look like.
We have our init function and inside the init function
in addition to this thing called self
which is the actual object that's being created or being initialized,
in addition, you can add as many parameters as you wish.
And that parameter is going to be passed in when an object gets constructed from
this class. And once you receive that data,
then you can use it to set the object's attributes.
This is what it would look like when we actually call our constructor.
We know that we can create an object by calling the name of the class and then
adding the parentheses. But if inside our init function
we have some additional parameters,
then we can also pass in data to those parameters
which will be used to set the attributes for that object.
So in this case, once this line of code has completed,
then my_car.seats is going to be equal to five.
And this is exactly the same as if we created our
my_car object first and then we said my_car.seats = 5.
It's completely the same.
But it does make it a lot quicker when you're creating a lot of objects that
need all the same attributes. Let's see how we would do it here.
We've got our init function already declared.
So if we wanted to pass over a user ID
when we construct our objects, we can add that as a parameter
and then inside the init we can say self.id,
so self.id is going to be the attribute that's associated with this class
and we can set it equal to the user_id that's passed in when any user gets
constructed. So now when we create our user,
instead of creating these attributes later on, at the time of construction
you can already see that we can add a user ID.
So let's give it the same ID.
And now let's add another attribute.
So we're going to pass in the username and I'm going to set the attribute
self.username equal the username that's past it.
Notice how in this case I've named my parameter user_id
and that value is going to become the self.id attribute.
So notice how these two actually have different names.
You can name either of these anything you want.
It's normally convention that you will see the name of the parameter be equal to
the name of the attribute, but you don't always have to stick to these rules.
Now let's go back to our constructor whereas previously it was empty,
now we have our user ID being passed in and I can now pass in the second
attribute, which is the username. So my username was going to be Angela.
And now we've created a new user,
which is user_1 from this user class
and we're initializing it with these starting values where the first value is
going to become the user ID which is going to be the self.id,
and the second value is going to become the self.username. So now,
if I wanted to print the user_1's username,
then I can simply write
user_1.username exactly the same way as before,
or if I wanted the ID, it would be user_1.id.
So now let's comment out the rest of the code and hit run,
and you can see we've got the user ID being printed here. Now,
remember that when you add parameters to the constructor
which is the init function,
you're now saying that whenever a new object is being constructed from this
class, it must provide these two pieces of data.
If we uncomment this and you try to run it, you'll see you get an error.
And it says that on line 12,
this user is being created from the user class.
But according to the init, we're actually missing two required arguments;
user ID and username.
So now when we create any object from this class,
we have to provide the user ID and the username.
But this is now much more convenient, right?
While we previously needed three lines of code, we now only have one.
Now sometimes when we're creating our attributes,
we might want a default value to start with.
And if at some later point in our program we want to modify it,
then we'll do it at that point.
But it doesn't make sense for all attributes to be initialized when we actually
create our object. So if, for example, in our case,
let's say that we were coding up the Instagram app, right? Well,
each of the Instagram users, they would have an ID,
they would have a username and they would probably have a follower count.
So they might have something like self.followers.
This is always going to start out as zero, right? You start a new account,
you're going to have zero followers. You might get some followers later on,
you might not.
But it doesn't make sense for followers to be something that we have to provide
whenever we construct a new object.
It seems very wasteful to have to always write zero
when you construct any object from this class. So in Python,
we can also provide a default value just as I've done here.
Instead of setting it equal to one of the parameters that's being passed in when
this class is being initialized, instead I'm just setting it to a value,
which is zero. Let's get rid of that from the initializer
because we now have a default value of zero.
And if I go ahead and print my, let's say,
user_1.followers attribute, and I hit run,
then you can see it's zero because all objects being created from this class will
have a followers attribute that set out to zero to begin with.