The constructor call can take arguments, which most often are the initial values for attributes that you want to keep in the object. Python uses a special method called
.__init__(), which it calls as part of the class instantiation process.
You may hear programmers refer to this as the constructor. That isn’t technically correct, but it’s similar enough to constructors in other languages that it isn’t really worth debating. When you write your own class, you likely are going to need to write a
.__init__() method to set it up.
All of an object’s methods, including
.__init__(), automatically get called with a reference to the object as their first argument. When you declare a method, you have to include this argument in the signature. By convention, in Python, this is known as
self. Technically, you can call it anything you want.
01:13 The compiler doesn’t enforce the name, but your fellow programmers may beat you, enforcing the convention through a different kind of argument. Let’s go revisit our circle from the previous lesson, this time as a class.
Logically enough, to declare a class, you use the
class keyword. Here I have declared a class called
Circle. The colon declares a block, and like with other blocks in Python, everything indented under here is part of the declaration.
By convention, the initialization method,
.__init__(), is typically included first. As you can see here, the first argument to the method, like all methods, is
self. When it’s called, it will contain a reference to the object.
Remember when I said
.__init__() strictly isn’t a constructor? This is why. When this method is called, the object has actually already been constructed. It’s being passed into the
.__init__() to be initialized by you.
This is also why
.__init__() doesn’t have to return anything. The object already exists, and you can do anything to it when it’s passed in as
self. A true constructor in the strictest sense actually has to return the newly constructed object. The second argument here to
.__init__() is specific to my
Circle class, and it’s the radius of the circle.
self is a reference to the object being initialized, you use dot notation to store it. I’ve gone with the typical pattern of naming the object attribute the same thing as that passed into the method, but there’s no requirement to do this.
03:08 This little chunk of boilerplate code actually kind of annoys me. Pretty much every single class you write is going to have this, and if you’ve got several arguments, you can have several lines of code devoted to this.
If I hadn’t put the
3 in this code, I’d get an error. As I did put
3, it gets passed into the constructed object, which then calls
.__init__(), passing the argument along. The
.__init__() then stores the
3 in the
self.radius attribute. Once
.__init__() is done, the constructor returns the new object, which I’ve stored in the variable named
06:02 It’s easier for someone else to understand your code if you use the conventions that everyone else does. First off, like variables, attributes on an object use snake case. That’s all lowercase, with words separated by underscores. Class names themselves use pascal case. That’s no underscores, but with capitals on each word.
06:25 If you’re coming from other object-oriented languages, you might be wondering about things like private, protected, and public permission structures. If you’re not coming from other languages, these concepts control who can see the attribute or call a method—the object, inheritors, or anyone. Python doesn’t really have this concept.
06:55 I used to write code where I tried my best to protect programmers from themselves, trying to stop them from doing things they weren’t supposed to. Python’s attitude is a little more permissive. It essentially says, Hey, this is dangerous, but if you know what you’re doing, we’re all adults here. So, how do you signal danger? Well, Python has public and non-public members.
07:16 Non-public members are indicated by putting an underscore in front of their names. This isn’t enforced in any way. People using the object can touch these attributes and call these methods, but you’re warning them that they’re not really part of the public-facing interface, and they might change. How intensely you use these ideas is kind of a style thing.
07:38 I don’t tend to use non-public values very much unless there’s an important reason why. For example, if I’ve got two values that must be set together, I might store them with underscores and provide a method for changing them.
07:49 At the same time, I have come across code that’s the other way though. One of the libraries I’ve contributed to once in a while is called Asciimatics. It’s a terminal-based animation and TUI builder.
08:01 The core maintainer really likes his non-public attributes. Pretty much everything is non-public, with special mechanisms for exposing the API. I haven’t actually had a chat with him as to why, but I suspect he used to write object-oriented code in another language and has carried the habit over.
You’ve already seen
.__init__(), and I’ve spoken about other special methods denoted by their double underscores. Key functionality provided by Python in classes is mostly built using these kinds of methods. Although they are a system thing, there’s nothing stopping you from using the same mechanism.
08:50 You can still do whatever you like with it, but you can think of it as an extra-special warning. If the single underscore is a note in the manual saying you probably shouldn’t do that, this is the sticker sealing your device shut, saying voids warranty. The sticker doesn’t stop you, but you really should know what you’re doing.
Become a Member to join the conversation.