 So, somebody was asking me if I can show more examples of how you use modules, the idea is the same thing, so if I have talk.py and I want another program Python program to use that talk.py, I put that program in the same directory and inside that a.py, I simply say import talk, it will find the talk that is in the current directory and then use it just like you do it in a standard interpreter, that is all there is to it, it is not very complicated, spoke about namespaces, the fact that they are simply mappings from names to objects, we looked at exceptions, how you can, what kind of exceptions are generated and how you can catch them and take necessary action and raise your own exceptions. Thing I did not mention was exceptions are basically you can create new exceptions of your own, by subclassing exception, there is an exception, it is a class, so you can actually create, it is a type, you can subclass this and create your own exception, but we are not going to do it in this, in the tutorial and the Python documentation has more detail on this. Okay, so let us get to classes, so what is the big picture of classes as follows, the main thing is you will let you create new data types, so basically a class is a template in order to create objects of that particular class, so think of it as the blueprint that makes you your Honda Accord, that notion of what defines a Honda Accord as against the Honda Accord itself, okay, so that is what a class is, so it is like a template. Please note that in Python a class is also an object, so it has properties and has behavior, so when you create a class it is just another object, the only thing about that object is when you call that object, it creates an instance, that is pretty much it, instantiating a class which is what I was saying is call that object creates the instance which is another object and the instance encapsulates the state and the behavior of that particular object. So basically classes in addition to just doing this, letting you create objects also let you define what is called an inheritance hierarchy, so let us say you are defining, you are creating something like a management tool for automobiles, for the automobile industry, so you will likely you will say that there exists an abstract thing called an automobile and the automobile has the following properties, it has this much power output, it has this rating, it has this fuel, it has so many wheels, number of wheels, you are basically saying that here is an object that has certain properties, you are vague about it, but you are saying that it does have some of these properties, for example even in biology you classify the entire all living beings into various types and there is a hierarchy, so a human being is a mamma, so you have what is called an is a relationship, so a Honda car is a car, a car is not a Honda car, a car is a general thing, a Honda car is a specific thing, I do not know why I picked Honda car, a car is an automobile, so a Honda car is also an automobile, so you have a hierarchy, Honda car, car, automobile, a means of transport, you can just go up an object, so you can actually go up and build a hierarchy and the beauty is each thing, so if you say a car, a car has certain properties and once you define those properties, they are done, you do not have to redefine those properties for a Honda car or for a Maruti car, you do not have to do it because they both inherit from the car class, so with classes you can actually create that inheritance state, so again it is about code reuse, the same way a python is a reptile, the crocodile is a reptile, so basically there is a notion of is a relationship, it is very important inheritance hierarchy, the other thing about classes in object oriented programming in general is that you need to think object oriented, you have to change the way you think, so you take some getting used to when you write OO code, so you have to resolve everything into objects that are interacting, it is not hard and once you start doing it, it becomes a habit to the point that you start talking always in object oriented form, but it is extremely powerful because it really lets you create, so what is the big deal? The big deal is it lets you create objects that mimic a real problem that is being simulated, so imagine for example you are solving some tracking of particles, so instead of saying I have this RA which has the X position, this RA that has the Y position, this RA that has the Z position and then you have a function that somehow manipulates these, you instead say I have points, I create a point object, I have an array of point objects and now I track these points, so you are talking in terms of points in your physical reality and in your code you are doing the same thing, I have some points, I have a list of points and these points are moved, so you have a function that says move, so you say move and the move is given as a list of points, so the point is when you write code, you start writing code that sounds like what you are actually talking about and this makes life very easy, it makes problem solving more natural, it makes it much more elegant, you can communicate these ideas much easier and it is a lot easier to create the code because you can think in this clear well separated notion, this is an object it does this, this object does this, this is how these two objects interact, it allows for phenomenal amount of code reuse when done properly and all of this goes without saying, if you do inheritance badly, if you say if you have a class inheritance hierarchy which says where an Honda car derives from a watch, it's stupid and you start doing things like this you get into difficulties but the instant you say a Honda car is a watch, you realize oh that's wrong, so again the point is the reality of the situation is directly represented in the code, so you just say it out loud, a Honda car is a class, no that's wrong, a Honda car is a watch, that's wrong, a Honda car is a car, yes that's right, so the language forces you to think in a particular way that's structured the way we normally think, so it makes code easier to create, easier to understand and it allows for code reuse, the reason is your car class defines everything for the car, only the specifics of the Honda car will be defined in the Honda class, therefore code is reused, the Marathi car uses the same one bit of code that's done by the car, only one thing changes, we'll see examples of this, the other thing is polymorphism which means depending on what the object is, the specifics of that object will be different, so in python how do you create a class, syntaxes as follows, you say class some name, bracket, object or multiple number of objects, the thing inside the bracket is what you are subclassing from and usually there's an object in python called object which is the base for all objects, so I can say class a object pass, so notice the use of pass here, syntactically I have to do something, I put a colon out there in the previous line, in the saying that there's going to be a block following here with some code, I don't want to do anything right now, so I put a pass, so now I can instantiate this class a by saying a, now a is a main dot a, this is defined in the namespace main is an object and a itself is a class, is that clear? In this case a has this, so let's see, a has a bunch of attributes, one of them is class, it also has a doc string which is the documentation which I have not written and a bunch of other things which I am going to ignore for the time being, so a dot class is the original class which is this, so a itself has say name, it also has other attributes like bases which are the base classes, so in this case I derived a from object, so the base class for a is object, do you know, is everybody familiar with base classes, how many of you don't understand what a base class is? So I said there is an object hierarchy, so we said Honda car, car, automobile, so automobile is like a base class from which car is derived, from which Honda car is derived, is that clear? So basically that is a relationship, a man is a mammal, so mammal is like a base class, the base on top of which you have a derived class called man, is that fine? So same way here, a has a base class called an object which is a generic thing in Python, everything pretty much is derived from, ultimately from, so in this case when I do a, I said a is, so I define the class by just doing this and instantiated an object of that class as a equals capital A, open bracket, closed bracket, a has an attribute called class which is the class of which it is an instance, the class itself, so a dot class, a dot class dot basis. Now the reason you have basis is you can also have what is called multiple inheritance, I am a man but I am also an Indian, so I can have two inheritance, but in general multiple inheritance is a bit of a problem because when you implement things you would be very careful. So I would recommend that unless you really are familiar with classes, do not mess with multiple inheritance, Python supports multiple inheritance, Java does not, so you cannot do it but do it with care. So now this f, the object here foo is just another object and in Python this is something I never mentioned, I can create an attribute of something by sticking it into it, so I can say a dot some junk, so I can set an attribute inside that instance. Now if I create b is a, b dot junk is a name error, attribute error, sorry, there is no attribute that this object has but b dot junk does work. So basically it is just an object, I have just created a simple object. Now let us get more complex. So in some more details, all attributes are accessed via object dot attribute, just like strings and lists the same notion, object dot attribute. Both class and instance attributes are supported which means as I said class is also a first class object, a class this a is a class, it is not an instance but I can say a dot junk, that is fine, it is just an object and now if I say b dot junk, I do not know if this works because it is going and looking at the class and now if I create a c, it is still 100. So I can create something that is common across all class instances by sticking that in the class itself. So these are called, in c++ they are called static, static members, static variables in a class. So in Python you can do that but you can also do it at the instance level as we saw. If I did a dot junk, it does not go to any other instance. Methods on the next thing which we look at are what give behavior to an object. So we have just looked at attributes, we created a simple object, we gave it at, we can set attributes into it and a method basically represents the behavior of the object. So crudely think of them as functions that belong to the object. So we look at an example. So think of this example my class derived from an object colon documentation string for the class, a class attribute and then I define a function f which returns hello world. Notice that the function has the first argument as self. So we will come back to this in a bit. But typically a method in a class has the first argument set to self. So let us run this example. This is the code, imagine I just typed it out. So I say talk.myclass.i that is 1 to 345 which I set. Now let us create an instance. I say is talk.notice that I am using a module is just I would have typed it here but it is nice conveniently sitting in my talk.py. I am just instantiating it from there. There is no difference. I have just introduced the notion of an namespace there. So I am creating an instance of this class. Now I have a which is talk.myclass object. Now I can say a.f. Note that I give you no arguments. I just hit enter and it returns hello world. So that is precisely what we have done here. Now notice I can also do this as talk.myclass dot f a it does the same thing. So basically a method is like a function where if called from the instance a the instance itself is the first argument. So I had self here right f self colon. I called a.f as a.f. I did not pass self to it. I did not pass any argument to that. If I wrote a function f self it is legal. There is no keyword called self. Now if I say f it is an error because I am not passed it an argument. But if I say f1 it works but for a.f it did not happen. What is a.f? This is the function. So it has a self but that self is not explicitly specified. So this is something that is automatically done. If it is an instance a is an instance of my class talk.myclass. If it is an instance then it is called when a method is called that instance is passed as the first argument always. But if I called this guy talk.myclass.f it is not bound to instance. It is the talks my class is f. So he has no idea who f is. So if I called this without any arguments it will say unbound method f must be called with my class instance as first argument. So in order to sum up this is what is happening. When you create a class definition like here a method there is just like a function except it is given the first argument as self. This when you create an instance this a here my class a is an instance of my class and a.f is called a bound method. A bound method is bound to a particular instance and every time you call this bound method the first argument of that bound method is the instance itself. Now this bound method is also a first class object. So I can say junk equals a.f no problems. How do I call junk now? What is junk? It is that same thing because junk is now a name that is a reference to a bound object a.f. So how do I call junk? That is it. So when you create a class you can set instance attributes class attributes. You create a function there the first argument of that function is self which is a convention you could have called it self x for example. That self becomes the instance that you are calling it for an instance. So when you instantiate my class a.f is a bound method that is bound to a such that when you call a.f the first argument is the instance itself. So now inside f for example class a object def create some data self and I can say self.data equals list. Now I say a.data is an error. I have not created the data. Now I say a.create data a.data is this list. Now if I had b is a, b does not have data. So self is conventionally the first argument for a method for a bound method. It is convention. You could define it as def f x no problem but then lot of people are going to curse you because it is not a convention. In the previous example a.f is a method object. In this particular case it is a bound method object. When a.f is called it is passed the instance a as the first argument by default and you do not have to call it. It is done for you. There are a bunch of special methods which let you do things on construction and on destruction and various other times. So I have only highlighted the one at construction time. So there is a method called underscore underscore init underscore underscore. If that method exists when you say a is my class that method will be caught. Same way when it destructs when the object is garbage collected a del method will be caught. There are other special methods by convention like underscore underscore add underscore underscore self comma object which will let you add two numbers. Let add two objects of the same type. So if you say I create a matrix a class matrix object I can define an add self comma another matrix. Then I return a matrix from there which is the sum of these two matrices. You can do all of these things. So you can add subtract divide multiply you can check for is something in this. So if you have a container object you can create a method called contains. These conventions are defined in these documents. So just visit them they describe exactly what you need to do. So here is a concrete example of how you create an object with instance attributes with a constructor created a bag which derives from my class. Notice my class is this which has a function f already defined which returns hello world. So bag now has an init and first argument is self. So when I say a is equal to bag this method gets called which means a dot data is set. Is that clear? So when the object is created first time the init method is by default called. So there are a bunch of defaults you have to remember. For a bound method the instance is passed as the first argument that self. So we are done with that. When you create an instance if there is an init method the init is called. You can do anything you want in that init. You can create variables you can create new objects delete other objects do whatever you want it is just another function. But usually it is used to create any instance attributes you want. Then you define any functions that you want like here add, add twice so on and so forth. Now you instantiate this object by saying a is bag a dot f will call what I have not defined f here. So how does it call a dot f? The second line here is a dot f. This is an inherited method. So it is defined over here. So it will return hello world. Now I can say a dot add one so it will add to data one it will append. So this is normal python code. The only thing is it is an inherited method you use self. So it is a self. This self. There is another method here. So here we see that add one add twice I end up with a is data being one two two. So that's it. So this is how you create and you can create as many as you want. Now supposing I want to derive from bag another bag you have to be careful. You have to make sure that in another bags init supposing you want to do something special in another bag. So let's say bag has data in another bag I want more data. Okay here. So you create an init for another bag you must call the parents init. So in C++ this is done automatically. In python it is not. So you have to remember to call bag.init self and here you are calling the unbound function. You are not calling a bound function. You are saying explicitly this is the parent class call this. The parent class if he has an init he would have called the other so it will keep going up and initialize everything that needs to be initialized. So basically when you do that you have the object say state set up exactly as how the parent has done it. And now you are free to do anything else. So you can say self. More data is something else. No problems. Now instead of doing this parent call there is a way to call it using what's called super. So getting back here the recap you create a class definition it creates a class object my class. Class object is any object so it has methods and attributes like here this is an attribute this is a method it's an unbound method. You instantiate a class to get an object of that class. And then when you call an instance object you say a.f self is passed automatically. The instance is passed automatically and it becomes the first argument. If a method called init exists it is a constructor. So at construction time it is called. Please note that init is just a normal function it is just a name init. So you can have arguments keyword arguments multiple arguments arbitrary arguments no problems. It's just a function. Similarly with dell and there are other special methods that I would suggest you look at these documents about. For inheritance you need to make sure that if your parent class has an init that you call it and define any derived functions you can derive any functions. Now the thing that's important in python is all methods in python are virtual. In C++ you have to explicitly say something is virtual. So if you don't know C++ you don't know virtual functions forget about what I said. Basically when you say a.f it's going to call the function of a called f that's it. You inherit through subclassing multiple inheritances supported. To answer your question there is no special public and private attributes. There are only good conventions. So usually when you say object.public this object.attribute without a leading underscore like here it's a public method. If it has a leading underscore it's usually a non-public method. It's a private method. This is a convention. So if you see something with an underscore and you're accessing it you really have no business accessing it. You're being bad. Okay so the last thing is polymorphism. So what's the big deal about polymorphism? I didn't say anything about it. So let's say I have a class called drawable which derives from object. This drawable object just draws. It has one method which says draw. Drawable really is not anything. It's a draw. It's like a car. There's no car. There's only a specific car. So I'm talking of a generic drawable object. What does a generic drawable object do? It draws. So I create a method called draw. Now I want to now say I want to create a real thing that can draw itself. So I say a square. So I do I write some code here to say drawing a square. I do a circle and it also does. It draws a circle. Now I want to create an artist that can take it is also a drawable which draws but which has a collection of various things that are drawable. So now let's say I'll show you the real code. This is just some pseudo code. If the artist has a draw method he will simply take all the drawables that he contains. So the artist can have a list of drawables. So I will simply say for object in for drawable in self dot drawables in my drawables draw the object. So I'll just show you a quick example. So talk, okay. So drawable is just what we saw. Square just prints draw square. Circle prints draw circle. An artist takes this. Notice the arguments here. It takes self and star args. Star args is what? Multiple arguments in the form of a tuple. So I convert that to a list and say self dot drawables equals list of args. Now when I draw the artist it will just draw everything inside it. So let's try this. So I say c is talk dot circle. Square is talk dot square. So I say c dot draw, draw circle. S dot square will draw square. So I say a is talk dot artist. And now I want to pass it any number of things. I could pass it nothing. I'd like to pass it the circle and the square. Now I say a dot draw. It's as simple as that. So now I have depending on what this object is, it's actually going to call either draw square or draw. I don't have to worry is this this type is that that type. No worries. I just create objects and let them do their thing. So you can imagine that if you're creating something very complicated that you can actually generate very simple looking code that does a lot and that does a lot in an intuitive map. That's what polymorphism is all about. First thing is how do you create standalone scripts? We just talked about everything on the Python shell. I want to be able to create a script that can be run. The way to do it is so you do whatever you do in a module, you create your functions do whatever. And then you check if you are running standalone as a module. So when imported name will not be made. So if I'm running the program directly by saying python talk dot pi, the name will be main. So if we are being executed, you execute this block. Is that clear? So as an example, if I do python talk dot pi, it prints this some list and does something. So if I now go back, it didn't print anything. I imported the code, but it didn't do anything. The reason is I defined this is just a normal module. Over here I said if name is main, do something. So when it's executed explicitly, name becomes main. And then you can do what you want. So that's how you create standalone scripts. The only other thing is the first line of your source code will have something that looks like this, which basically tells Unix that if you see a script like this, you interpret the contents of the script using Python. That's all. No magic to it. One very handy feature is called list comprehensions. Let's say I have wedges, tomato, carrot. I'm going to simplify it. I don't have much time. Now I want to create a new list containing each of these with an upper. How will I do it? One way is doing v is empty list. Then I say for x in wedge v dot append x dot upper. Upper is a string method. Each x becomes tomato or carrot. And I'm appending that to the empty list. v is this. But this is like four lines of code. With list comprehensions, I can say v is x dot upper for x in wedge. Boom. Done. What is the error? I didn't call the method. I just said v dot upper. So if you ignore my errors, it's just one line of code. So x dot upper for x in wedge gives you this. Same way if you look at I created a range object. So what will this be? 0, 1, 2, 3, 4, 5, 6, 7. Not 8. I find all the even values like this with one line. I can find all the odd. I can print the square of the even values like this. I can do this. And now I can do a two way for loop. I can say xy for x in even for y in odd. So basically here the only new thing that's introduced is the if block here. So for x, for wek, for x in wek, if x percentage 2 is 0, what does x percentage do? It's yes. So if it perfectly divides, if the reminder is 0, it's even. That's it. So it's a very convenient shorthand and it's very efficient also. It's done in C underneath. So it's very efficient. So I've listed out a bunch of very useful IPython features. And this is kind of verbose. It's meaningless for me to sort of draw on about each of these. So it's there in your printed slides and it's also there in the PDFs. So look at these and experiment with these when you are on an IPython session. So basically IPython supports input and output caching, which means all the stuff you've typed in is stored. All the stuff that it outputs is stored. Inputs are in in capital IN. So if I say, for example, IN, it has all the inputs. Same way, OUT will have all the outputs. Underscore, double underscore and triple underscore are the last three variables that were outputted. You can get the history of what you've typed. I can say hist minus in without the line. So now we're going to cut paste this and stick it in a file. You can log your entire session, which means if as you type it's actually saving it to a file by using log start log on and log off. Run has several when you do run. So for example, if I do it executed talk that by now, if I do run minus D and breakpoint at something, it'll actually run that under the debugger. So it's extremely handy, which means I say I want to stop at line number 40 on this script. So it'll go there, stop there and it'll run your code under the debugger and give you a debugger session. You can inspect variables, play around and stuff. There's a variable called PDB. So if you make a mistake in your code and you do run and you have PDB on, it'll actually go and put the debugger at the error point. Okay. So if you want, I'll show you a demo. So def. So when I imported, there are no errors. Now if I say talk.test, it gives me an error. But I want to go to that location in the error. So I just say PDB automatic PDB has been turned on. And now if I do talk.test, it gives me a debug around where I can actually type and see what is nonsense. So it says name error. I can figure out the error here. Now I have Python and I have the power of Python. I can introspect, check values, do stuff and the interpreter. You can do profiling of a script with run minus p, which means what is profiling, familiar with profiling? Profiling basically tells you which part of the code is executing how long. So if you want to do a time analysis saying, okay, where is my function? Why is it so slow? It'll actually tell you, give you information on where it's slow, where it's fast. You can go in and then speed up those functions. Time will time the script. So it'll tell you how fast the script, how long did it take to run. You can record macros, which means if you run five lines and you see you're keeping on repeating those five lines, plot this, get this, change this, you record a macro and you can type the macro name, it'll execute those five lines. Then you can use an edit. So you want to edit source code from Python, you can say edit. So I suggest for more help, supposing there's something like you do a question mark, iPython will tell you about something. There's a macro, you want to learn how to use a macro, type it, put a question mark, it'll tell you what to do. You can change directories. So you say cd something, it'll change to that directory. You can access the shell. I think I did this, I did echo something. So bang command runs a shell command and returns it output. You can grab the output of the command you ran. You can use bookmarks, which are very neat. So I can say cd to some directory and then say bookmark some name. The next time I don't have to type that long directory name. I can say cd that bookmark name, it'll go there. So long as there's no conflict with an existing directory with the same name. If you really want only to use the bookmark, you say cd minus b, then it'll only go to the bookmark directory. So basically extremely convenient. Supposing you've typed a lot of stuff and you want to save that to a file, very useful. You did a lot of experimenting and you want to save all of that. You can say save lines file name or say file name lines, it'll save it. And for more help, just type %magic. All these commands are magics. It'll tell you all the existing magic functions and give you plenty of documentation on each. Okay, file handling. Again, file is straight forward. If you want to read a file, a text file, you simply say open name of the file name. The method read will read all of that content of the file into a string and return it. The read line function will keep on reading one individual line at a time. Read lines will read the entire thing as a set of lines. So let's just try this. Open. I'm going to open the talk file. So f dot read. Ooh, gives me all of this. It's a string. So I can say underscore is the last variable. I didn't save that, but underscore is there. Printing the code. That is the code. So I know again, say f is open. I finished reading the file. I'm going to reread it. f is open talk. So f dot read line prints the first line. So it can keep on doing this. But then I can say lines is f dot read lines. It's a list. So the 10th line is print this particular line. So you can read all the lines. Further, files support iteration. So you can say for line in file. So if I say f print line, it works. You close a file explicitly by saying f dot close. It's a good idea to always do that. And then you can't read the file anymore. There are other methods like tell, which means you can move to a particular byte in the file and seek things like that. You can write files. Same thing. The last argument you pass as w default argument for this is read. You want to write a file, you just put a w. You can create a file. So if I did it for talk dot pi, my talk dot pi is gone. So I'm not going to do it. But you can do it and to write, you just explicitly pass it strings f dot writes the string, the string, the string and you have to explicitly put new lines. So if you want a new line, you put a slash in math module, we're going to do a lot more math, but there's a module called math. So say import math. See, I can't do square root here. There is no square root. But math defines square root. So I can say math dot square root, math dot pi, so on and so forth. So again, you do math dot tab and find out, figure out for yourself what there is. These are basically real, real valued math functions. C math gives you complex value. So if you have complex numbers, you want logarithm of a complex number. C math defines it. There's a random module. It's not a, it's not a random module, but it's a module that gives you random numbers. It's a very good random number generator. But these basic modules, math, C math and random are default. They're always there. So any Python installation, you can find these. So they're convenient. When you want to time, it's another thing that you need to do often. You want to time your code. You can use the time module. Time dot clock will give you the current clock. You run some instructions, time dot clock again, you get something. The next time, the difference of the two is the wall clock that's elapsed. But I find that I Python is the most convenient way to do this. You use I Python's time and time at macros or magics. Same way, you can use I Python's run minus p to do a profile. Bunch of odds and ends. There's a built-in called dir. So given any object, it will give you the attributes of a given object or the attributes that are available in the current namespace. So if I type dir, I get all of the variables that are currently available in the namespace. If I do dir on math, it will give me all the attributes in math. So it's a generally useful method. The built-in called type, it's another function. When given an object, it will give you the type of that object. So if I say type, I hope a is, there's no a. a is a string. So if I say type a, it will tell me type string. str and repr basically, if you're given an object, if you do str of the object, it will convert it to a nice string form. There are methods called isInstance and isSubclass. So if I take, so I'm going to instantiate a class. Okay. Remember that bag is subclass from my class. Another bag is subclass from bag. So I can now ask the question is instance. So is instance a my class? Is it an instance of my class? Yes, it is because it is another bag is derived from bag which is derived from my class. There are, there's another statement called assert. Read it up. There are a bunch of useful modules like csv which let you read up csv files. You're going to need that. Pickle lets you do serialization. I don't think we're going to cover it. And the sys module has something called an argv, which gives you the arguments passed to a script. So if you say import sys and then say sys.argv, it will give you a list of all the arguments that were passed to that particular script. So as an example, if you look at talk.py, the last lines import sys print sys.argv. So if I run python talk.py, it prints talk.py, a list. If I did some arguments I'm giving it. Talk.py minus a minus b. So it gets the arguments and you can actually do processing. You can actually check. There are other modules which will let you to command line parsing. You can build a sophisticated command line in general. Okay, the best place to get more information on documents of various standard modules is the module reference. So it's again all free available documentation.