Types and Classes

00:00 In the previous lesson, I gave an overview of the course. In this lesson, I’ll be covering the type() function, the type type, and classes.

00:10 Everything in Python is an object. It’s deja vu all over again. Thanks, Yogi. Each of the objects has a type. The type indicates its nature. A number has the type int, text has the type str, and an instance of a person object has the type Person class.

00:28 The type() function tells you what type an object is. Let’s go play with it in the REPL. Let me start out by writing a list.

00:42 Calling the type() function on it returns the fact that it is an object instance of the list class. Here’s one of the cats … and the type of that is str. Interestingly, it’s turtles all the way down. Here’s the third letter of "tiger", whose type is also a string.

01:09 That’s a bit different from other programming languages that make a distinction between a character and a string. Strings and their substrings are both strings in Python, right down to single-letter instances. How about when you write your own class?

01:26 I’ve kept it simple here, creating an empty class. Here’s an instance … and hopefully that’s not a surprise that the type of the instance is the Dog class. The __main__ prefix on this is because I’m in the REPL.

01:44 If the class were declared in a module, you’d get the module name as the prefix instead. Let’s try something else. That’s the max() function from the built-in library and that’s max’s type. Handy that Python distinguishes built-in types from others, huh?

02:07 Let me create a class inheriting from Enum

02:18 and get an instance. Goodfeathers shout out for the win. There’s the instance and its type. That shouldn’t be too surprising, as that’s how it was built. Do note that it isn’t calling it a class but an enum. We’ll come back to that later.

02:38 Let’s go a little meta. The type of the instance is Birds, but what is the type of Birds? Well, it’s a class called EnumType.

02:51 Same as Enum itself, which sort of makes sense, as Birds inherits from Enum. There’s a transitive thing going on here. Let’s go grab EnumType

03:05 and look at it. Now that’s a little weird, isn’t it? The type of EnumType is type. Remember Dog? Yep, the same thing. Same thing actually goes for built-ins.

03:23 Type of a list, type of a float, they’re all type. The type type is the top level of the class hierarchy. In fact, you can think of the type() function the same way you think of the str() function. When you call str() on something, it returns its str equivalent.

03:41 When you call type() on something, it returns its type equivalent. It bears repeating, type is the top of the hierarchy. Let me show you. Yeah, the type of type is type, which you get by calling type().

03:56 Does that clear it up for you? This is the first of the brain-melting bits on the way to metaclasses. Let’s go talk about classes, and hopefully it’ll become a little clearer.

04:08 Python has had classes and objects from almost the beginning, but how they were built changed in Python 2.2. In this version, they added the idea of a base object that everything can inherit from. Up until Python 3, both the old style and new style of classes was supported.

04:27 If you’ve done some object-oriented coding in Python 2 and had your class declaration inherit from object, this is why Python 3 got rid of the old style.

04:38 You can still use the new style declaration inheriting from object, but if you don’t, Python uses the new style anyways. This saves some typing, but it can cause some confusion for folks who are going back and forth between Python 2 and 3. Hopefully, that’s fewer and fewer of you nowadays.

04:55 Let me demonstrate these different class declarations in the REPL. I’m in a 2.7 REPL. Let me just prove that.

05:08 See, 2.7.18. Now let me declare a class using the original syntax.

05:18 If you’ve used Python 2’s new style, note that I have not inherited from object here. This can actually be a source of a tricky bug in Python 2.

05:27 If you mean to use the new style and forget the object inheritance, your classes may not behave the way you expect. Anyway, let’s play with the old style for a bit.

05:38 There’s my apple instance. And the .__class__ attribute of an object indicates what class it’s from. Here it’s showing that apple is Fruit declared in __main__. Again, being in the REPL is what causes __main__ to be the module name.

05:58 Running type() on apple gives instance. That’s an old-style thing. Running type() on the class itself gives classobj. Again, an old-style thing.

06:09 All right, out with the old, let’s talk about the new. In this case, new is kind of relative. It was introduced in Python 2.2, which was released December 21, 2001.

06:23 I suspect some of you may have been born after this new thing. Anyhow, the relativity of new notwithstanding, let’s use it.

06:36 The new-style class declaration inherits from object. You can actually come at this the other way around. Inheriting from object is what distinguishes this as a new-style class.

06:46 Without object, you get the old-style class. Offer limited to Python 2, offer may not be valid in some states, buyer beware, caveat emptor, et cetera, et cetera.

06:58 carrot is an instantiation of Vegetable. carrot.__class__ is __main__.Vegetable. The only obvious difference between the string representation of the old and new class is the old class includes an object ID reference, and the new one does not.

07:18 The type, on the other hand, is quite different. This is the kind of result you saw when I was playing with the type() function before. The type of a new class object is the object’s class, where the old-style object’s type was instance.

07:36 And like you saw before, the type of a new-style class is type. Back to my type of type being type found with the type() function. Okay, that’s Python 2. How about Python 3?

07:52 I’m in a new REPL.

07:58 3.11.2. New REPL, new class.

08:06 Let me instantiate some dessert. Sundae, yummy sundae. I apologize, Bono. And the type of sundae is the Dessert class. This shouldn’t be a surprise.

08:21 You’ve seen this already. The point I’m trying to make is in Python 3, you no longer need to inherit from object. Python 3 uses the same syntex as Python 2’s old-style classes, but actually produces new—that’d be 2001-new—style classes.

08:39 This was done because the old style isn’t supported anymore, and there’s no need to make Python 3 programmers type out the extra inheritance. Since Dessert is a class, its type is type.

08:53 For compatibility’s sake, you can still do it the old new way.

09:05 Love me some gnocchi. Type of the instance is the class, and the type of the class is type. Essentially, although not necessary, you can inherit from object in Python 3 and get the same result as not doing it.

09:23 This makes compatibility easier when you’re writing scripts that need to work in both, say 2.7 and a 3 variant. Let’s get graphical and visualize the new style.

09:36 Starting with my sundae instance, which was created by the Dessert class, and the type of Dessert is type, and the type of type is type.

09:49 Does the picture help? Saying the type of type is type is fun. All right, I’ll stop now. The type() function can be used as a class factory as well. In the next lesson, I’ll show you just that.

Become a Member to join the conversation.