 The Python language was first created in about 1990 by a Dutch guy named Guido van Rossem, who is still pretty much the guy in charge of the language, but formal responsibility has been handed over to an organization called the Python Software Foundation. The Python Software Foundation effectively decides what's proper Python and what isn't. There are a few different implementations of Python, but by far the most popular is the one created by the Python Software Foundation itself called Cpython, so called because the Cpython interpreter is itself written in C. When people talk about Python, they usually have in mind Cpython. The other implementations like Jython aren't used nearly as much. Jython as the name hints at is a Python interpreter written in Java. IronPython is an implementation written for the .NET platform and PyPy, very interestingly, is an implementation of Python written in Python itself. Just to be clear on that, it's a Python interpreter written as a Python program. One reason these three other implementations aren't used nearly as much as Cpython is because they're less mature. In fact, they all lag behind in features. Jython, for example, doesn't include any of the features that have been added to Cpython in about the last four years. A couple years ago, Python started a big transition from version 2 to version 3, and the big deal about Python 3 is that it not only added new features to the language, it actually changed some features of the existing language. So this means that code written for Python 2, in most cases, won't run under Python 3 and vice versa, so code written for Python 3 won't run with a Python 2 interpreter either. Because of these changes, it's going to take a long time for code written in Python 2 to be updated to run for Python 3 and for some programs that in fact will never happen. So this means that the Python Software Foundation can't immediately stop development for Python 2. They have to still keep releasing new versions of Python 2. So it's almost as if Python 3 and Python 2 are actually separate languages. So far, the transition to Python 3 has been really quite slow. It's been almost three years now, and it'll easily take another three years before most new code written in Python is written in Python 3 rather than Python 2. As it stands, many people today still choose to start new projects in Python 2 rather than Python 3 because they need to use some piece of code which is written in Python 2 and won't work with Python 3. Despite all that, we're going to be covering Python 3 because I think Python 3 for one is going to be the future eventually, and also though it's by no means a radically different language, the changes are mainly quite small. The changes generally are for the best and make things simpler. So that's why I prefer to teach it. If at any point the need arises for you to work with Python 2, it shouldn't be hard at all for you to pick up on the differences after you've learned Python 3. So what kind of language is Python? Well, it's nothing too surprising by now. It's an imperative language and it's dynamic just like JavaScript and just like Pigeon. And in fact, semantically, it's very, very similar to JavaScript and also Perl and Ruby. The one big difference compared to JavaScript is that Python is a more explicitly object-oriented language because Python has a formal mechanism for classes. To be clear, nothing in Python forces you to create your own classes so you can write all of your code in a procedural style. But typically, most Python code is written in a mix of the procedural and object-oriented styles. So jumping in, here's a snippet of JavaScript code and here's the equivalent in Python. The first thing to note here at the top, comments in Python begin with a single hash character rather than two slashes as in JavaScript. And then in the next line, a function is defined starting with the reserved word def short for define rather than the word function. And the two other things to note about this function definition is that the header ends with a colon and then the body of the function is written indented underneath just like in Pigeon. We don't use curly braces to denote bodies. We just use indentation. And you can see the same thing in the if the if header ends with a colon and then its body is indented underneath the if. So Python syntax is indentation sensitive like Pigeon, not freeform like JavaScript. And as we'll see later Java and C and most other languages have freeform syntax. In fact, Python is really the only major language which is indentation sensitive. The last couple differences to note here is that first the condition in the if x less than three doesn't require parentheses around it. And last thing to note here in Python, we can create local variables just by virtue of assigning to them. So here x, we don't have to declare that that's a local variable, it's just implicitly a local variable. As we'll see later, this actually creates a little bit of an issue when you nest functions inside others, just like you can do in JavaScript. Because that means in Python then we have to in some cases explicitly denote that a variable is not local to that function, even though we are assigning to it in that function. Usually, though, this isn't a problem. So it's just a nice little stylistic allowance that we don't have to declare our local variables. So in summary here, you can see that in some ways Python is more like Pigeon, but in other ways it's more like JavaScript. Like in Pigeon, comments begin with a hash character, code is indentation sensitive, statements don't have to end with semicolons, and local variables and functions are implicitly created by assignment. But unlike Pigeon and like JavaScript, expressions in Python use infix notation rather than prefix notation. The basic data types in Python should be nothing surprising. They're basically the same things we saw in Pigeon and JavaScript. The only thing to note is that Python uses the terms lists and dictionaries where JavaScript uses the terms arrays and objects. And what JavaScript and Pigeon call null in Python is called none. And yes, it's written always with a capital N, which is actually kind of aggravating because that makes it harder to type. Every data type in Python is a class. And for every class, there is an actual object representing that class. So here in the diagram, each of these represents an object, which is a class. Boole here is the Boolean class stirs a string class into the integer class for integer numbers, list for lists, dict for dictionaries, and function obviously for functions. And like in a lot of object-oriented languages, the classes in Python are arranged into a hierarchy with a class called object at the top. So the arrows are indicating here that, for example, the bool class is a direct child of the object class. When you create your own classes, they will by default directly inherit from object. So the class Natalie here is a child of the object class. You may, however, specify that your new class inherits from some other class, say here Aaron inherits directly from Natalie, and Roy is inheriting directly from the int class. Notice though that for any class you create, object is going to be the ultimate ancestor. This makes sense, though, of course, because anything you create is a kind of object. Keep in mind that the idea of a class is we can produce from it other objects, which are instances of that class. And in fact, every object in Python is an instance of some class. So what about class objects themselves? Well, the answer is that they themselves are instances of the type class. I suppose Python could have called it the class class, but they decided that was confusing. Actually, in Java, that's what they chose to call it. In Java, there's a class class, but in Python, there is a type class. So what's really confusing here is the relationship between type and the object class and the other classes is the arrow from type to object here is indicating type is a direct child of the object class. But that's just the inheritance relationship between these classes. Type is a child of object. But very strangely, the object class is itself an instance of the type class. And also it's an instance of itself. So think about this, the object class object itself is an instance of the type class, because the object class is a class. However, the object class is also an object. So it is also an instance of itself. And then the converse is true of the type class. The type class is an object. So it's an instance of the object class, but it's also a class. So it's an instance of itself. So let me just repeat that object and type are instances of each other and also instances of themselves. So objects and type have this weird incestuous relationship. The same is actually true for every class object. Every class object is an instance of both the type class and the object class because they are both classes and they are objects. But for every object which is not a class, that object is just an instance of its class and then indirectly there are instances of that class's ancestors. So for example, if we create a function, that function object is an instance of the function class and in turn it is also an instance of the object class. And say if we create an errant instance, that object is an instance of the errant class and in turn an instance of the Natalie class and the object class. To create an instance from a class in Python, we invoke it like a function. So here for example, assuming Natalie is a reference to the Natalie class, then if we invoke it like a function, this expression returns a new Natalie instance. Now we can do this with any class but of course for some of the built-in classes like say function, we wouldn't create functions this way. To create a function object, we use a def statement. For any class though which isn't built into the language, this is what we use.