Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Adding Attributes to a Python Class

In this video, we start building our Dog class and fill it out with attributes.

We can instantiate our Dog class like this

Python
philo = Dog("Philo", 5)

We can access the instance attributes with dot notation.

Python
print(philo.name)

00:01 Welcome back to our series on object-oriented programming in Python. In the last video, we learned how Python classes can define both class attributes and instance attributes. To better understand how classes are instantiated, let’s head over to the Python shell. All right.

00:18 So, I’m here in the Python shell and I’m going to start by creating a new class Dog, and I’ll just write pass, which will tell Python that we want a blank object. Now, if I simply call Dog() like this, Python will instantiate that and it will actually tell us the memory address of our new Dog object—that’s this fancy-looking number right here.

00:41 Now, let’s create another Dog object. Do you think that this new object will share the same memory address as the first one? Or is it going to be different? If we press Enter here, you’ll see that this new object has a slightly different memory address.

00:56 This is because each instance of our Dog class is unique. Sure, both objects are created from the same class, but they’re still different objects in memory.

01:06 If we actually filled out the class with an initializer, we could assign different attributes to each object. And just to drive this point home, I’ll create two new dogs and I’ll store them in variables a and b.

01:20 So, at this point, a and b are both variables that point to objects in memory—objects of type Dog.

01:28 We can easily check if they’re the same object by using the double equals (==) operator. And if I press Enter, we will see that they are not; a and b point to different Dog objects, even though both objects are blank.

01:41 And to prove that both of these variables are of type Dog, I’ll use Python’s built-in type() function, and I’ll give it a as an argument.

01:50 As you can see, this variable is pointing to an object that was instantiated from the Dog class.

01:58 Now, let’s finally build a real Dog class and create some real Dog objects. I’m here in Visual Studio Code, and I’m going to start by defining a new class called Dog.

02:09 Next, I’ll type species = "mammal". This is going to create a class attribute for our Dog. This means that every new dog we create is going to be a mammal, by default.

02:22 But now, I want to write some unique instance attributes, so I’ll add in an initializer to the class by typing out my .__init__() function, and that will require three parameters: self, name, and age.

02:36 Remember, we don’t actually supply a value for self, but we do need to do something with these name and age parameters, so we’ll tell Python we want to assign them to the new object being created.

02:47 Here, self references the current object being created, so self.name = name means to assign the name parameter to this new dog’s .name. And that’s it! We’ve created our Dog class.

03:02 Let’s actually use it now. We’ll create a new variable called philo and that is going to point to a Dog object. We create a new object by typing the class name followed by parentheses (()), almost as if it were a function.

03:17 When we do this, Python is actually going to call the initializer behind the scenes, and so we need to supply our name and age arguments.

03:25 So here, I’ll make the name "Philo" and we’ll give him an age of 5. Next,

03:31 let’s make another dog named "Mikey", and he will have an age of 6. Congratulations. If you’ve been following along, you’ve just created and instantiated your first class. Right now, we have two dogs—one named Philo with an age of 5 and the other named Mikey with an age of 6.

03:50 But how do we actually access the data inside of these objects? To do that, we can use the access modifier, which in Python is the dot (.).

03:59 You’ll notice that when I type philo., Visual Studio IntelliSense—which is incredible, by the way—appears, and it shows me all of the attributes that I can access. So, let’s do this.

04:12 I will delete this new line and I’ll replace it with a print statement. I’ll say "{} is {} and {} is {}", and then I’ll call the .format() function on this string, which will allow us to populate these blanks ({}). Because we have four blanks, we need to pass in the .format() function four arguments.

04:33 So, I’ll pass in philo.name, philo.age, mikey.name, and mikey.age. These are going to access all of the attributes of both of our objects.

04:45 Next, let’s see if both dogs have the "mammal" attribute. I’ll type if philo.species == the string "mammal", then I want to print "{} is a {}" and then—just like before—I’ll fill in these blanks ({}) with Philo’s .name and Philo’s .species using the .format() function.

05:10 All right, let’s right-click and Run Code, and on the right side here, we can see exactly what we’re expecting. Philo is 5 and Mikey is 6, which is from our first print statement. And then, because Philo is a mammal, we also saw Philo is a mammal printed to the screen.

05:28 Now, let’s change things up a bit. After we create the new Dog objects, let’s change their attributes. So, I’ll move up a few lines and I’ll type mikey.age = 7 and then philo.species = "mouse". Now, pause this video and take a look at this code and think about what it’s going to print. All right, let’s take a look.

05:54 Now, we see that Philo is 5 and Mikey is 7. That’s because we changed Mikey’s .age after we created the object. And notice that we don’t see Philo is a mammal anymore—that’s because we changed Philo from being a mammal to a mouse, and again, we did that after we created the object.

06:13 When we assigned new values to these attributes, the initializer wasn’t used. That’s only used when we create new objects, not modify their attributes. Also, if you notice here, both Dog objects are completely independent of one another, even though they came from the same class.

06:31 Even though I changed Philo from being a mammal to a mouse, Mikey is still a mammal. And that right there is just scratching the surface of the power of object-oriented programming. In the next video, we’ll take a look at instance methods, which is the fancy Python way of saying class behaviors. I’ll see you there.

Avatar image for malcolmgandrews

malcolmgandrews on Sept. 30, 2019

I don’t want to be a pedant but a Mouse is a Mammal.

Avatar image for richardojeda1985

richardojeda1985 on Oct. 24, 2019

ok what if you are working in a class with user input? how would you call the str method??

Avatar image for Austin Cepalia

Austin Cepalia RP Team on Oct. 27, 2019

I’m not exactly sure what you mean by “working in a class with user input.” There are a few approaches you can take if you need user input. The first one is to instantiate the class with the input already stored in a variable like this:

class Person:
    def __init__(self, name):
        self.name = name

name = input('enter your name: ')
person = Person(name)

Or you could ask for user input in the __init__ method like this:

class Person:
    def __init__(self):
        self.name = input('enter your name: ')

person = Person()

str() is used to convert a value into a string. input() returns a string, so I’m not sure why you would need to call that. If you’re talking about getting a string representation of the object instantiated from your class, you can do something like this:

class Person:
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return 'this object has name ' + self.name

name = input('enter your name: ')
person = Person(name)
print(person)

This is beyond the scope of this course, but str defines the string representation of an object (This is similar to overriding ToString() in other languages). When we pass the person object to the print() function, it calls str under-the-hood and prints the string representation of the object. You can learn more about that here Let me know if you have any other questions!

Avatar image for kwf777

kwf777 on Nov. 2, 2019

Why do you use {} and format instead of just printing the attributes?

Avatar image for Austin Cepalia

Austin Cepalia RP Team on Nov. 5, 2019

@kwf777 This was my first course. I was under the impression I needed to follow the article exactly, which used .format() because it’s a bit older. I use fstrings in all my courses now :)

Avatar image for Oleksii Potapenko

Oleksii Potapenko on Nov. 13, 2019

At 5:35 output is changing without any run code.

Avatar image for sideproject8

sideproject8 on Dec. 17, 2019

Please re-record this with the new f-strings. Might be silly to ask but as someone who is really trying to learn python, this small issue just keeps messing me up and takes me out of the flow of your courses, when other videos on here use f-strings. Please and thank you.

Avatar image for mnemonic6502

mnemonic6502 on Jan. 18, 2020

Regarding species not being printed second time around after species was changed to ‘mouse’ was useful to highlight, but took reviewing. Could have been made clearer by saying something like it’s not printed out on right because yada yada etc (rather than assuming the learner knew the lack of output as a parallel from your technical explanation).

Avatar image for Lokman

Lokman on Feb. 27, 2020

Hi Austin,for clarification that class attributes is a permenant attributes compare instance attributes that can modify even outside of class code blocks.

Avatar image for Ricardo

Ricardo on April 11, 2020

This video was awesome!

Avatar image for Zarata

Zarata on April 14, 2020

A rose by any other name smells as sweet … I’m a Java person, but not hugely “formally” trained. Thus, if the high keepers of the Java flame make a distinction between class attributes and instance attributes, (properties), I don’t remember. I simply define class vars in Java and give them default values, or leave them null and give them values during construction – the practical results always seem the same. (I’m bypassing visibility, protection, etc.) Here in Python the class and instance var terminology functionally doesn’t seem to make a lot of difference either, though I do see the conceptual difference. What I’m trying to express is that as soon as you say

__init__(self,myinstanceattr)
    self.myinstanceattr

then “myinstanceattr” becomes an inextricable part of every self example of the class just as a class attribute would be – the only difference is that “classattr” would have a pre-assigned default value (which I find can even be None). However, the instance attributes are “required” to be assigned values during the creation of the class instance (haven’t seen an automatic default init yet, though can define an equivalent). Once you have an instance, both the class and instance attributes can be accessed and modified using the “.” operator. So, long short: I’ll be waiting to see in the next vids if there’s any deep down difference behind “class” vs. “instance” vars, like speed of access or storage locations or something.

Very good presentations. Clean, well thought, great delivery. Thespian? Experienced teacher? Little things make me suspect you’re a C++ or Java guy also, either now or in your beginnings.

Avatar image for Austin Cepalia

Austin Cepalia RP Team on April 14, 2020

@Zarata Not thespian, but I do have a lot of experience teaching. Particularly with kids who don’t respond well to boring teachers. You were close with the languages too, my background is primarily C# and .NET :)

Avatar image for Cory

Cory on May 1, 2020

So in essence everything in python we’ve been learning is oop? Is that why certain built in functions work with str.object and not with tuple.object?

Avatar image for Thomas J Foolery

Thomas J Foolery on June 22, 2020

How does Python enforce encapsulation?

Avatar image for Joseph Flanagan

Joseph Flanagan on Oct. 18, 2020

I might be wrong, but I think there’s a mistake at 1.28 (when you are comparing the two classes). Doesn’t a == b return False because your class doesn’t have __eq__ method rather than because the memory addresses are different? If you wanted to test for the latter, wouldn’t be a is b? Of course, they are different objects, but == is the value equality operator.

Avatar image for Geir Arne Hjelle

Geir Arne Hjelle RP Team on Oct. 18, 2020

@Joseph Flanagan, agreed, it would have been better to use a == b in this case.

However, this is the kind of mistake that somehow still works. When a class does not define .__eq__(), == is essentially equal to is. More precisely:

User-defined classes have __eq__() and __hash__() methods by default; with them, all objects compare unequal (except with themselves)

(Source: docs.python.org/3/reference/datamodel.html#object.__hash__)

Avatar image for henrytirla

henrytirla on Nov. 21, 2020

Great course! What about attributes that are defined out of the __init__()? Are they still instantiated when it is called eg class Person:

def __init__(self, name):
    self.name = name
    self.age= age
    self.astrosign = astrosign

Will the last two attributes be called when the init is called?

Avatar image for Bartosz Zaczyński

Bartosz Zaczyński RP Team on Nov. 23, 2020

@henrytirla Attributes declared outside of .__init__() or any other method are attached to the enclosing class. They’re defined even before any instance of that class exists and are shared across all existing instances.

For example, consider this Person class:

>>> class Person:
... 
...     counter = 42
... 
...     def __init__(self, name):
...         self.name = name
...
>>> Person.counter  # There are no instances of this class yet
42
>>> alice = Person("Alice")
>>> bob = Person("Bob")
>>> alice.counter
42
>>> bob.counter
42

However, when you wish to change the value of a class attribute, you should always refer to it through the class name instead of a particular instance. Otherwise, unexpected things start to happen. You’re creating an instance attribute with the same name that masks the class attribute:

>>> alice.counter = 15  # Defines an instance attribute in Alice
>>> alice.counter
15
>>> bob.counter  # Bob has no such attribute
42
>>> Person.counter  # ...so, it delegates to the class attribute
42 
Avatar image for charles7276

charles7276 on April 5, 2021

Would it be better to set the species in the __init__ function? For example, self.species = 'mammal'. I guess I’ve just never seen it done the way shown in the tutorial.

Avatar image for Bartosz Zaczyński

Bartosz Zaczyński RP Team on April 6, 2021

@chananya7276 “Better” is a highly subjective term because it all depends on the circumstances 😉 This lesson introduces the concept of class attributes, and species was defined as one for the sake of example.

Avatar image for mrudavshukla

mrudavshukla on Aug. 8, 2021

Hey Austin, not able to understand the phrase at 03:56, “… we can use the access modifier, which in python is a dot(.)”. Aren’t access modifiers public, protected and private in general?

Avatar image for HomoDeus

HomoDeus on Nov. 28, 2022

I am new to Python. If class attributes is what I understand is default, would changing it as per your example make sense?

Avatar image for Ariba S

Ariba S on June 5, 2024

Can I get clarification that a class attribute when changed by one instance, is changed for all instances?

Avatar image for ahairshi

ahairshi on Aug. 19, 2024

The class variable is shared among all instances of a class, rather than being unique to each instance. It is called static variable in Java.

Become a Member to join the conversation.