 Okay, so I stopped at this point where I said names are bound to objects and I think that is somewhat confusing so I am going to elaborate a bit on that. So getting back to names are bound to objects. So let us say, clear, I say A is 1. Now A is a name which is bound, so there is a one object, so the instant I did this, one an integer has been created and sitting somewhere in memory. His name A is associated with that, okay, it is as simple as that. Now I say B is equal to A, so B is 1. Now if I say A is 2, what do you expect to happen to B? B is actually 1. Because when I do B equals A, B is now a name bound to the object to which A is bound. A is bound to 1, I say B is equal to A which means I have another name B which is referring to the same object. So now if I change A to something else, B does not change because B is still hanging on to 1. So is that clear? So basically forget about the notion of pointers and C++ references and things like that. Just keep in mind that a name, any name is simply a name that is bound to an actual object sitting somewhere. So in Python there are two basic kinds of data types. So basically there are a bunch of basic objects like numbers, floating point, integers, long, complex numbers, strings, tuples, lists, dictionaries, functions, classes so on and so forth. So these are basic object types. The types are classified further into two. They are called mutable types and immutable types. Now immutable types are like numbers, strings, the special type called none and tuples. Immutables cannot be changed in place. So think of the number 1. You cannot change 1. 1 is 1. On the other hand you think of something like a list. Not introduce the notion of a list but think of a list. I can add something to a list, I can remove elements from a list. So I can actually change the object fundamentally. Immutables are those which cannot be changed. So numbers, strings in Python are immutables which means you cannot change a string. You can only create new strings. You cannot change a string in place. There is a special type called none which basically means nothing. It is none. So it is a special object called none. You will find that it is an extremely useful object when you are doing programming in Python. And there are tuples. Tuples are collections of objects but you cannot change the tuple itself. Mutable types like lists, dictionaries, instances of classes etc are mutable and they can be changed. So as I talk you will see that I use the word object. So what is an object? So you need to understand what you mean by an object. So basically I am going to give you a loose and informal but pretty handy description. Computer scientists forgive me for looseness but this is a useful description. An object is a particular instance of a general class of things. So here is a simple concrete example. Consider the class of cars made by the Honda company. The notion of a car or a Honda Accord does not give you a car. But the actual car you see on the road is a particular instance of a Honda class. So you have a Honda Accord. It is a particular type of car and you have the notion of a Honda Accord. So every time you see a Honda Accord you can actually say yes this is a Honda Accord. That is not a Honda Accord so on and so forth. But the actual Honda car standing in front of you is a particular instance of that general notion. So objects are basically these things that you have and they have certain properties. So an object is a general term that is used all over the place in Python. So you just understand this kind of loose description. Why are objects important? The reason is just like your Honda car you can create objects in Python under programming language. And this object has two things. It has attributes. So for example you can have the color of your Honda car, the power of the engine, the seat type for example you can say it is leather or what is the upholstery whether you have a music system inside or you do not so on and so forth. So these are attributes of that car, features of that car and then you have behavior. The fact that a car behaves in a particular way that you have an accelerator which you can push, you have a door which you can open and you interact with that car based on that behavior. So in object-oriented programming language the same idea holds. You create objects, objects that contain some kind of data which represents their attributes or their state and they have what are called methods which are kind of like which are functions that are associated with this object that give it a particular behavior. So is that clear? Basically an object has some attribute, some state, some data and it has what are called methods that let you do something with that object which means you have behavior. And the example is kind of complete even if you look at any object around you it is an object. So it has attributes, it has a particular behavior. You can think of anything in this manner. Now the reason this is important is when we write programs especially more sophisticated and complicated programs we think object-oriented. We do not, we do not explicate it but we always think, we think in terms of okay there is a point here that point is moving here. You do not think of an XYZ triplet that is moving from here to there or something in some coordinate system. You abstract it and you call it something and you denote it, you give it a name. Same way you create objects. So ideally you want to create a programming language but you program in the same sense. You create objects and you make these objects interact with each other. So that is the idea about object-oriented program and why it makes a difference. So basically programmers create objects and manipulate them through methods to get things done. So in Python everything is an object. Okay? And do not really worry about it. Just have the idea that it is an object. And if you ever need to go back and understand it, think of real objects. They have, they have state and they have behavior. It is pretty much it. So we will get back to classes and things later but this notion of an object is very powerful and very useful. So let us get on to numbers. So the first is integers. So you can say A is 1, 2, 3, 4, 5, minus 1, so on and so forth. But integers have a fixed binary representation which means there is some integer beyond which you cannot go. But Python has a special type called long which you create by saying integer followed by a capital L as you see here. These are of any length. And if you are writing pure Python code, if an integer overflows it becomes a long automatically. So if you actually create something and say A is 1 and for loop it forever, it will just go longer and longer and longer and longer. No problems. Python will work with that. Okay? So longs can be as long as you want. Then you can create floating point which is basically similar to the double precision number in C. There is only one floating type, float type in basic Python. And then you have complex numbers. And each of these straightforward, the floating point numbers can be created either standard decimal notation or you can create it with an exponential notation. As I said, you can use Python as a calculator. You can multiply these basic types, divide, modulo, reminder, so on and so forth. The print statement basically prints whatever you give it. So if you give it some arbitrary object and the object can be made into a nice string form, it will convert it to a string form and print it. So we will see. You will use print as you go along. It is pretty straightforward. Print has this feature where you give it a comma. You can print multiple arguments. You can say print A comma B comma C comma D. The complex data type which I have not described is written by two ways. This is one way, 1 plus 1j. Now C is a complex object and C dot tab will show me all the methods. It has a real attribute and an imaginary attribute. I could also say C is complex if you do not like the J syntax, 1 comma 1. When I type C, it converts it to some string form and shows me 1 plus 1j on screen. There are a whole class of these functions called built-in functions. So when you start up Python, you have these built-ins all the time. One of them is abs, ABS, which will give you the absolute value of that, the magnitude of that complex number. You also have a Boolean type in Python. You define it as true capital T, small true will not work. See here. You can define standard logical operations like not. Not of true is false, of course, or an end. And in Python, these are explicitly written. So you say not of this, not bang. I can see. Let us get on to strings. So strings in Python are, they have lots of ways in which you can write strings. The first one is a simple string. This is a string. You see that it is using the back quote, single back quote on both sides. It is not left quote and right quote. It is the same quote sign. You can embed the other kind of quotes, the double quote inside single quote strings. And vice versa, which means if I could put double quotes, reverse with single quotes inside. And it works. Obviously, if you terminate it at a point with the other, with this symbol, it ends the string. So it is smart enough that it lets you, you do not have to escape the other quotes inside a particular string. Now if you have a string and you want to span it over multiple lines, you can basically do this. You can say a long string spanning several lines and then you put in backslash in order to escape the string. This is the standard, just like you see. But this is so common that Python has a special type of string called a triple quoted string where you do not need to do this. You simply put three quotes. So I will show you an example. So let's say s is 1, 2, 3, I can use this quote or the other quote. And then I can type this is a very long string spanning many lines. Three quotes, it's done. So s is a long string. If I say print s, I have that entire string. So it's a convenient way of writing long strings. And often your documentation strings are just these long strings. Now strings have a bunch of methods and bunch of things you can do with them. So let's say you define a word. The variable word is a name that is bound to a string object, which is hello. So now I can say two times word plus word. It produces hello, hello, word. So basically if you multiply a string with an integer, it multiplies the number of strings. But then what would happen if you multiplied it with a fraction? It doesn't make sense. So if I did s star 2, I'll get two strings. But if I did s star 2.5, I get an error because it doesn't know what you mean when you say half of a string. There is no meaning for that. But it does know what it means when you say two strings, just two strings. You can add strings. So I can say s plus s, that's two strings. I can add them. Obviously you can't subtract strings. So the other thing you can do with strings is you can index. And in general, Python indexing starts from 0. So over here with the word hello, word 0 is h. Word 2 is l. Word minus 1 is counting from the reverse. So I'll do this a little slowly. So word is hello. So word 0 is h. So what would word 3 be? l. Word minus 1 counts from the last. Very handy. So it's o. Word minus 2 l. Word minus 4 e. Word minus 100 is an error. Word 100 is also an error. You can see one thing here is Python's error reporting mechanism. So it says you have an index error. So it's a very specific error messages. In any programming languages, in any programming language, please remember that error messages are extremely important. And please pay attention to that. So when you see an error, it has a meaning. There's a reason there's a message there. Here it says the string index is out of range. So you clearly know what's wrong. That you're indexing a string and it's the wrong value. Strings are immutable. Which means I could not say word 0 equals h. There's another built-in apart from ABS. It's called len. It's a very useful built-in. Len of s will give me the length of the string. Which is 71. Len of word is 5. You can also define what are called unicode strings. I'm not going to go into any depth at all on this. But just know that if you have a u prepended here, it becomes a unicode string. So if you specify the code page and so on and so forth, you can actually type in multilingual things. And the other thing is raw strings. In this we will encounter again sometime later. So typically in C type strings, you have backslash n as a new line. So I'll show you that. So say s is hello slash n word. So if I print this, I get hello new line word. So slash n is a new line. Sometimes I don't want the slash n to be interpreted as a special character. I want it to be the raw string slash n. In which case I say r is r hello slash n word. So if I do print r, it prints it as hello word. So raw strings let you create strings where you do not automatically convert slash sequences into special characters. So slash n, slash a, slash b, they're all special symbols, slash t is tab. So it will not convert those to specials. Now strings also have what are called methods. So strings are objects. So if I create a is hello world and I say a dot starts with, so let's see that. So s is hello world, s dot starts with, it will return true if s starts with a specific string. So if I say starts with hell, it returns true. Does it start with this? It doesn't. Same way you have an ends with and then you have what's called upper which means you given a string it will convert. It will generate a new string. It will not change the string in place. It cannot change strings in place because they are immutable. So you have a dot upper gives you hello world in caps. A dot lower will give it back in lower form. A dot split is another method which is very handy, which basically splits this sentence based on an argument. The default is space. So supposing I have a list of words, hello world, it will split it as two items, hello and word and return a list which we will cover next. But the idea is a dot split will split the word, split the sentence into words. There's another method called join. So I'm not going to elaborate this here. The other thing that's often useful is doing what is called C style formatting. You typically say printf string something is something percentage so on percentage d, percentage s and so on. The same syntax is supported in Python. The only difference is you put a percent at the end and then give a tuple of the arguments. We'll do tuples later but the idea is you put brackets and you say the arguments you want converted and it will convert it. So I suggest you try this out later. I'm not going to elaborate this. But the idea is strings are objects that have a bunch of useful methods. They support C style format strings are possible. And they support various methods that are very handy to use. The next type we're going to look at is lists, the built-in type. Now lists are mutable unlike strings. They are also indexed at zero which means the first element of a list starts at zero. The last element is minus one so you can count reverse. The length of a list is always found by length of that list same built in just like length of a string. So here are some examples. If I create a list, I can create a list with any kind of items unlike other languages like C. You don't have to say a list is just a list of strings. You can put the list of lists, a list of strings, a list of floating points so on and so forth. So here is an example A is spam, X, 101, 2, 3, 4. A zero is spam. So you create a list note by the square bracket. So I can say A is 1, 2, 3, hello, Python, oops, I created a list. A zero will give me the first element minus 3 is 1, 2, 3, 4, minus 2 is 100, this element. The next notion is slices which are not done in strings with the same notion holds. So supposing I want the second character to the penultimate character and I want that list. I say A1 colon minus 1, it starts at 1 sorry which is the first, the second element and ends at the penultimate. So in this case, spam X 101, 2, 3, 4, I get X and 100. So this is called slicing. So as an example, here is our string S. I can say what will S2 or 5 colon minus 1 give me? Space whirl. Now if I want the last guy also, you don't specify the last index. The same way if I wanted from the first to say the first 5, I get hello. Please note that these are new strings. Each of these is a new string. So slices let you define things like a sublist or a substring. So you have in this case A colon 2 plus bacon comma 2 star 2, this is another list. You can add two lists. If you add two lists, you get a new list which is the sum of the two lists. So many of these things are kind of intuitive. So you just experiment with this and you will get the hang of it. The same way as you have multiplication with strings, you can multiply lists also with integers. So if I say 2 into list, it gives me twice that list. Basically takes this. So you get in this case 2 into A colon 3 will be what? What is A colon 3? 0, 1 and 2. So it span x and 100 that twice and add to that book. Is that clear? Now lists are mutable. None of these examples I changed the list. I only got elements from the list. I got sublists. I didn't change the list. Just like you could have done with strings. So I can now say A of 2. What is A of 2? 100. So A of 2 is A of 2 plus 23. Which means I am setting back this third element which is 100. So the new list becomes span x 1, 2, 3 and 1, 2, 3, 4. You can also replace elements on a list. So if I say A of 0 colon 2, it basically takes out the span x and replaces that sublist with the new list I have provided. So item assignment works in two ways. You can assign individual elements. You can assign an entire array or a part of an array. So for example, if I had A here, I wanted to change the entire array in place to say 1, 2, 3. I can do that. This will do it. So I say A bracket colon bracket. So by default, if I don't specify something on the left, it starts at 0. If I don't specify something on the right, it's the end. So now A becomes 1, 2, 3. I could have done this as well. And what will this give me? An empty list. So you can assign items individually or on slices. In addition to these kind of things, you can also, there are a bunch of list methods. Length of a list of course is not a method, but it's a built-in method, built-in function. You can reverse a list in place. When you reverse a list, it does not return a new list. It reverses it in place, which means span x and ham, span x 100, 1, 2, 3, 4 will become 1, 2, 3, 400 x in span. As seen here, you can append elements into a list. So I can say A, let's say 1, 2, 1, 3. So I can say A dot append and I can append a list to it. I can append, okay. So let me append first 4 to it. So A becomes 1, 2, 1, 3, 4. Is that clear? Everybody here with me? Now I can say A dot append, I'm appending a list. So what do you think will happen now? So you'll have a list of lists. So I have 1, 2, 1, 3, 4, 100, 120. I could go in and now say, now how do I access the 120? Okay. So A minus 1 will give me, will give me what? Will give me the last list, which is 120. That list in turn I can again access. So I can say minus 1, minus 1. There's another method called extend, which given a list will just add the elements of that list into the existing list. So if you look here, if I'm extending it to 1, 2, it doesn't append a new list. It actually adds the items of that list here. There's one more thing which I like to do. Supposing I say A dot append, A, wouldn't this work? It actually does. So I can say A minus 1 and it's A again. The beauty is again, go back to notion of A is just a name that's bound to an object. So there's an A, there's this list object sitting there and there's just this name bound to it and there's a reference that can go as long as you want. So you can say A of minus 1, of minus 1, of 0. So it basically works. So that about covers lists as far as this tutorial introduction is. Get on with tuples. So lists have methods and I encourage you to go on ipython, create a list. Do list.object.tab. Look at all the methods, play around with the methods, experiment, do whatever. The computer is not going to blow up. Have fun. Tuples are again similar to lists in the sense that they're collections. They're collections of anything, but they are immutable. Which means I can access them like so, t0, t1, t2, t minus 1, minus 2, minus 3, so on and so forth. But I cannot change them in place. Which means once you create a tuple, you're set. You can't change it. But say t is 1 comma A. It's a tuple. So which means I can't say t of 0 is 100. I can't do that. But t of 1 is, t of 0 is what? 0. What about t of 1? It's A. So I can now say t of 1 dot append 1000. And that works. The reason is the object inside that tuple can be changed. That is not immutable. The tuple itself is immutable. It's not what it contains. So this is an important thing. Just because you put something in a tuple, it doesn't mean you can't change it. The next very important and pretty fundamental data type in Python is a dictionary. So think of dictionaries as associative maps. Think of them as arrays not indexed on integers. So let's say I want to create an address book with the index being the name of the person. I would use a dictionary for that. Of course, real programmer will probably use a database for that. But dictionary is a pretty good starting database. So basically dictionaries are indexed by keys. And the keys in this case have to be immutable. Is that right? They have to be basically hashable. But let's not get into the details. The basic idea is you can create a dictionary. So let's say dict is a dict object. We'll see how to create it. Dict key can be set to a value. The method keys returns all the keys of that dictionary. The method values returns all the values corresponding to the keys. And the method has key returns if a key is in that particular dictionary. So examples. So here we create an example where you have, supposedly a telephone directory. And the way you create a dictionary is using curly braces. So this curly and this curly define the dictionary. So you could create an empty dictionary by saying that's dictionary. But in this case, they have been filled out with a few basic values. The key in this case is jack. And the value is 4098. Followed by a comma for the next item. Another key and this. And now you can access the elements by using the key. In this case, there was no key called Guido. So this particular line tell Guido equals 4127, injects a new key called Guido and assigns the value to 4127. As you can see here. Same way accessing an existing item in the dictionary is as simple as del jack. And you want to remove it, you use del. Del, del, shape. I am going to do a simple version. So if I print d now I have this. I say del, d, b. And now d has only a. You can do the same thing with lists. I have not shown it there. Tell.keys gives us the keys. So if I say d.keys, I can say d, d becomes that. Now I am not restricted to using the keys as only strings. So I could do d of 1 is, that's fine. It works. So and I am not restricted to using only a particular type on the right-hand side. So you can mix most types. This is extremely handy. Okay, so that covers about dictionary. So let's just do a little bit more about the methods. So it has a bunch of methods. Again I encourage you to explore this on the interpreter. So clear will clear remove all the items from D. Pop will remove a specified key. d.values will give me the values as we saw. There's one thing called items. So if I say d.items, it actually returns a list of. So what is this? This is a list of tuples, each containing key value. Key value, key value. This is useful. We'll use it later. But that's about it. So you have basic data types, numbers, booleans, none. None does nothing. It's basically used as a placeholder sometimes. And it's used to say a variable is uninitialized and things like that. But it really doesn't have any methods or it's an immutable thing that you can't change. You have strings, you have lists, you have tuples and you have dictionaries. So now we have basic data types. We can actually start doing things with Python. We now need to know how to do control flow. And control flow in Python is primarily established using if, l if, else. For loops, while loops. And that's it. There are only three looping constructs in Python. If, for and why. In addition to these, you have special keywords called break, continue and else. Which can be used when you're looping. Finally, you have a special keyword called pass. So sometimes you want to say, if the value of this string is equal to crescent, is equal to IIT Bombay to this, if it is equal to some nonsense, do nothing. In that case, you use a pass. You say pass, pass will do nothing. It will basically, it's used when you syntactically need it. But you don't want to actually say anything. You want to do nothing. It's like doing nothing. It's like an empty photo. So because Python requires indentation to describe scope, you need to put something in there to indent to say that this is that block I want to execute. And pass basically is an empty statement. So here's the if example. Before we get there, I'm going to introduce raw input. So let's say I want to input something from the user. I want to write a program where the user is going to have to type some value. So you can use what's called raw input. Please enter a number. So it prompts me. And I can now type in something here. It's not a number, but it returns the out value you see here is ASD, ASG, whatever, whatever I typed. So it returns a string. So I could have as well done this. Please note it returns a string. It does not return a integer. It just returns a string. Whatever the string the user typed. But if I want an integer from this, how would I get it? I can use int of s. Same way to get floats. You use float and it'll take the string representation and convert it to a float if possible. So what would happen if I said int of one? What do you think would happen? I'll get an exception. It'll say value error. I have no idea how you want me to convert one to one. So again, note that when you make a mistake, you don't get a segmentation fault. You're not kicked out of the interpreter. You get a clear error message that says you made a mistake. Fix it. And you just continue working. Okay. So now we can get to the if example. So I'm basically asking the user for an integer. And int converts it to an integer. And now I say if x is less than zero. So this is how you do tests. So x is less than zero, greater than zero. Not equal to zero. All of these are very similar to any other language. So I'm not going to belabor that. Do something. And all of this stuff, which is indented to the right one level is executed if this is true. Same way of x is zero. Do this. Do this. So you have if, elif. So if condition colon execute block, elif condition colon execute block. Finally, else. If all of that fails, else colon do whatever else. Now, in addition to this basic if you can also check for whether something is contained in a list or in a dictionary. So let's say we have a list called cat window defenestrate. And you say if cat in A. So A is what? A is this list. So this is very intuitive syntax. If there is a cat in this list, you print me out and it does that. You could also say if cat not in A. So I can say, do I have A? Okay. So if one in A, that works. Okay. On the other hand, if I say if 10 not in A, it is correct. There is no 10 in that list. The same way with dictionaries. You can have, if you have a dictionary, you can say if croc in pets, print pets croc. Okay. Is that clear? So same way here, this in condition only checks for the keys. It does not check for the values. You could have also done if croc in pets dot keys. So let's do that. So if one in D, that works. But I could also say if one in values, that also works. So basically we have done if now. Next thing is for loops. So you have, again, let's say we have a list, cat, window, defenestrate. So for x in A, print x, length of x. So this prints cat, three, window, six, defenestrate. Well, so for loop basically follows the structure. You have a for which is a keyword, x, the variable over which you are going to iterate. Okay. So now we saw that you can iterate over a for loop. Please note that the x here, so the for loop starts, you say for x in A. So what is x? x have not defined anywhere. So every time you iterate over the elements of that list, x changes from cat to window to defenestrate in sequence, cat, window, defenestrate. So setting up that variable is taken care of by the form. You don't have to declare x is a string type and will be set so and so nothing. You just say for x in A it's done. And x doesn't have to be anything specific. If the item in the list is a list, x becomes a list. The same way you can do this with dictionaries. So you can say for i in D, print i. This iterates over again the keys. So for example, for i in A, this A is a list, print i, prints the elements of the list. D is a dictionary that looks like this. For i in D, print i gives me the keys of the dictionary. So it's the same kind of notion. But often it's not enough if you just have the keys. You also want the values. So let's say you have a dictionary of this. I want both the keys and the values. Knights, this dictionary basically has a method called iter items. And then you can say k, v in the knights.iter items. You could also use items, print k, v. So this is called tuple expansion over here on the left side. So it says, so let's do this in little more detail. Let's say I have two variables, x, y. I want to set x, y to some two values. The way you do it is you'll say this is 100, 200. It works. The right-hand side is a tuple. The left-hand side is a tuple. Python understands this and automatically sets x to 100 and y to 200. So the same thing happens when you do this. k, v in knights.iter items. Iter items iterates over the items, which is key value, key value, key value pairs. So every time in the loop, you get k, v being the key and the value. Is that clear? So there are ways to iterate, standard way by which. So two important things you can use if something in some container could be a list, could be a tuple, it could be a dictionary. It will find if this thing is contained in that. And then you can do for, where you say for some variable in some container, it will iterate over the elements of that. And for dictionaries, you have a special thing called Iter items or items, which will let you iterate over the key value pairs. Now often when we do calculations, we want to iterate over an index. We don't want to iterate over the values. So let's say you have a list of 100 items and you're looking to say I want for i in 1, 200. Get me the values of this. The way in Python to do it is to use the range built in. The range built in returns a list starting at by default 0, ending at what you specify here with this particular step. So again, I encourage you to say range question mark to look at the documentation. But range 5, just for now, will give me 0, 1, 2, 3, 4. It will not give you the last element. So in this case for i in range 5, print i, i star i will give me 0 and whatever you see here. Now clearly if you have a string and I want to find the elements of that string and you want to do it like this, let's say I have string as s. How would you do it with this? You would say for i in range, length of the string iterate. Is that fine? Same idea. So s is this string for i in range length of string print i, s of i. So I have just found the elements of that particular string. The other useful thing with looping is often you have a list and you want both the index and the value. So this is something you will find you need when you are programming and there there is another built-in called enumerate. So if you have any iterable, you can basically say i, x in enumerate a you get the index and the item. This is just another looping construct that is useful.