Attributes
00:00 In the previous lesson, I showed you how to write your first class in Python. In this lesson, Iâll dive deeper in how you associate data with your object through attributes.
00:10 So far, youâve seen me use attributes on instantiated objects, but Python actually supports two different kinds of attributes: the instance ones that I just mentioned, and class attributes.
00:23
Instance attributes are specific to an object, while class attributes are shared across all objects created from the same class. Inside the class, the instance attributes are assigned and accessed using dot notation on the self reference, while class attributes are referenced directly on the class.
00:42
Letâs go look at some examples. Iâm going to create a new class that counts how many instance objects are created from it, and Iâm going to name it ObjectCounter.
00:58
Inside the class declaration block when I create an attribute this way, itâs a class attribute. That means itâll be common across all object instances constructed from this class. Remember, to get at an instance inside the class, you need self, and thereâs no self here, so itâs on the class instead.
01:19
Letâs write .__init__().
01:28
Each time you create a new object, .__init__() gets called. So this is a good place to increment the counter that counts how many instances there are. To access the class attribute, I use the name of the class instead of self, and then here Iâm incrementing its value by one.
01:46 Let me instantiate an object â¦
01:52
and there it is. That ugly bit of REPL response is because I havenât defined how to represent this object. The default display shows the name of the class, the module itâs in (__main__), and a reference address.
02:09
An object inherits the attributes of its class, so you can access the .num_instances attribute through the object. Letâs create two.
02:24
And the .num_instances counter has been incremented,
02:31 and as the value is on the class and not on the object, itâs shared across all the objects. Accessing it on one shows the same result as accessing it on two.
02:46 And now that Iâve shown you you can do that, Iâm going to tell you that you shouldnât. Generally speaking, I prefer to use the class name when accessing class attributes.
02:55 It makes it clearer that what youâre using is a class attribute, and it also avoids a subtle mistake. And what mistake is that you might ask. Good question. Follow along.
03:08 Youâve seen class attributes can be accessed through the object, and you saw that the class attribute is modified through the class, but itâs important to note that it can only be modified through the class.
03:22
You see, Python supports the dynamic addition of attributes to an object, not just in .__init__(), but anywhere you have access to the object.
03:32 Python also supports overriding values. When you assign an attribute on an object, Python sees this as being an object attribute. If you already have a class attribute with the same name, it gets overridden, hence the subtle bug.
03:48 You might think youâre changing the value of the shared attribute, but youâre not. Youâre creating a new one on the object that happens to have the same name and overriding it.
03:58 Letâs go look at an example of this fiasco in practice. Same class as before. Thereâs my object. And like before, I can access the class attribute on the object. And
04:20
as a reminder, thatâs the preferred way: doing it on the class itself. I mentioned I can assign attributes on objects dynamically. Here, Iâve added a new one called .value, and itâs an attribute just like anything else.
04:37
You donât have to do it inside of .__init__() in order to assign a new attribute.
04:46
Here, Iâve done the exact same thing. Iâve created a .num_instances attribute and added a value dynamically. Since it has the same name as the class attribute, the objectâs attribute takes precedence. So the class attribute hasnât changed,
05:10
but the object attribute is 85. This would be why I prefer to use the class name. Itâs clearer and avoids this problem. If you donât have the class handy (say itâs declared in another file), you can get at an objectâs class through the .__class__ attribute.
05:29 And as thatâs the objectâs class, you can get at its attributes from there. See? Although Python doesnât stop you from accessing class attributes from the object, itâs a good habit to strictly access them from the class itself to avoid confusion. If youâre coming to Python from a strictly typed compiled object-oriented language, I suspect youâre thinking this is a giant foot gun.
05:55 I will admit on occasion I accidentally add a new attribute because I misspelled the attribute I wanted. A compiled language definitely catches these kinds of problems.
06:05 The other side of that coin, though, is some truly powerful things can be done with the dynamic nature of Python. A lot of the magic behind SQLAlchemy and Djangoâs ORM and how they map to databases is built on top of the dynamic nature of Python, so you gain some power at the risk of certain kinds of bugs.
06:24 Whether thatâs worth that trade-off is for you to decide when youâre picking your language for your project. Youâve seen how classes and objects have attributes and methods.
06:35 In the next lesson, Iâll dive deeper to show you properties, Pythonâs equivalent of getters and setters.
Become a Member to join the conversation.
