 Good morning everyone. So, what we covered yesterday was getting started with the interpreter, the basic language interpreter. We showed that there is a basic Python interpreter and the IPython interpreter. We showed you how to use both. Then we looked at the basic data types and operators that are available in Python. These are mainly numbers and sequences and the Boolean type. We looked at how we can use all of these and we also looked at certain common patterns in the sequence types. Then we moved on to strings. We did strings in some detail and then we did conditionals which is basically the if, if, else loop conditional. Then we looked at loops which are the while loop and the for loop. Then we looked at input output. We looked at the print statement. We looked at some string formatting. We looked at raw input and how you can get up, you can present a prompt to a user and get back what they type. Then we looked at input and output through files. How do you read a file? How do you write to a file? Then we looked at how to create functions. So, in term period we solved a little problem of parsing a data file which had about 40,000 records. Those were processed and run and used in order to calculate the average marks obtained in mathematics in region B. Then we went on to functions and did functions in some amount of detail and we stopped with doing functions. So, the next topic will be tuples, dictionaries and sets. We will try and finish that, try to finish that in the next session. So, the next topic is tuples. Tuples are very similar to lists. The only difference when you construct a tuple is that you give it a parenthesis rather than a square bracket. And just like lists tuples can contain heterogeneous elements. The elements do not have to be all of the same type. So, I can have integers, floating point numbers, strings, so on and so forth. You could have other tuples. You can have lists inside a tuple and other kind of objects as well. Note that when you are assigning this to a variable, it is not always necessary to use a parenthesis. So, if you say a equals 1, 2, 3, a will become a tuple. However, if you are writing code, it probably makes it more explicit to somebody else if you actually put it in brackets. So, that people know that you are actually using a tuple. Now, accessing or indexing through a tuple is the same as any other sequence. Remember that tuples are also sequence types. So, you can use the similar indexing notation. Indices start with 0 and give it positive indices or give it a negative index based on all the discussions we had yesterday. You should be able to clearly follow what it does. Similarly with slicing. So, if you slice it, you will get a fresh tuple which represents whatever tuple that you have asked for. The only issue is that you have to keep in mind is that tuples are immutable, which means I cannot once I have defined and created the tuple, I cannot go back and change the values inside that. So, if I have a tuple of say 1 comma 2, let us switch to the interpreter. If I say t is 1 comma 2, I cannot set t of 0 is equal to 3 for example. It will give me an error at this point. Now, there are some interesting things that you can do with python thanks to something called tuple unpacking. Now, supposing I have two variables, I am trying to swap two variables. I have a and b, I want to swap a and b. So, normally the code to do that would be temp equals a, a equals b, b equals temp. This is the usual swapping variable approach that you would use in say c or something, but in python it is possible to do it this way instead. You can say a comma b equals b comma a. So, a lot more convenient to do especially because you do not have to deal with this temporary variable. What is happening here is this is also true when I am doing things like if you look at the interpreter, I can do x comma y equals 1 comma 2. What is happening here is something called tuple expansion. If I print x, x is 1 and y is 2 type of x is integer. So, essentially what happens is in python, it looks at the left hand side and the right hand side. They are both looking like tuples. It tries to assign one to the other. Now, obviously you have to make sure that the number of elements on both sides is the same. If not, python will not know which one to set to what. So, for example, if I did x comma y equals 1 comma 2 comma 3, this is not going to work. Why? Because there are only two elements on the left, which two go where is not obvious. There is no unambiguous unique way of doing this. So, it will raise an error. It will set too many values to unpack. I do not know how to deal with three values because on the left hand side there is only two values. However, if I did this, what would happen? Is this legal or not legal? This is legal because now type of x would be a tuple. So, what you have to keep in mind is when you are doing tuple expansion, things like this a comma b is b comma a, you have to make sure that the same number of arguments are there on the left side and the right. Same number of elements are there on the left side and the right side. You have to make sure that that is done. Note that you do not have to make any considerations on what the variables are. So, if a is 2.5 and b is hello, this will continue to work. It does not matter what the quantities are. It just matters that they have the same number of elements here on this side and that side. So, for example, this is exactly what is happening here. It is called tuple unpacking and packing. So, tuples that is pretty much all there is to it. What you have to realize? One thing you have to remember is, so supposing I will do a little bit of advanced concepts, let us switch to the interpreter. So, let us say I say t is equal to 1 comma 2 comma 3. Now, I cannot change t. So, if I have to do something, I have to really create another tuple. So, let us create this little interesting tuple where I create an empty list. So, those of you who are trying to take the test now, please stop. Class is going on. That was an attempt. We had spent more than half an hour trying to test and unfortunately, there were many problems for many people. Many people it worked. So, just forget about taking the test right now. We will come back to doing the test later. Please pay attention to the class right now. We will come back to the test. Do not worry about your test scores. This is only a dummy test, so that we are able to test whether the software works. It took us a lot of time to make sure we are able to get something working. We know that it works. There are some issues which we will sort out. Please ignore the test and do not send any chat messages on test. This is not working because it is probable that the test has been actually disabled. So, if you take the tuple that I have just created, empty list 2 comma 3, you basically now are in a position where I have. So, what is the first element of this tuple? tf0 is a list. Now, I cannot say tf0 is some one or something, but can I add elements to that tf0? Can I do tf0 dot append 1? The answer is yes, you can because I am not changing the tuple, but I am changing what is contained inside the tuple. That is tuple cannot help you there. So, now we print t. You see it is one. However, I still cannot do tf0 is equal to some one or something. No, that would not work. So, if you contain, if the tuple contains mutable objects inside it, you can continue to mutate those objects that are, that it holds. You cannot change it directly. You cannot change the contents of that tuple. That is what the tuple contains. Those objects can by themselves be changed, but you cannot tell the tuple to contain different objects. The tuple contains one set of objects and only one set of objects cannot be changed once it is constructed. So, you cannot, there is no tuple methods of, you cannot sort a tuple. So, for example, let us see what the methods there are. You can only count an index. Notice there are only two methods without underscores count an index. Two more useful tricks that are again not explicitly in the slides. The first is how do I convert say a tuple to a list and vice versa. Turns out that if I want to convert a tuple to a list, it is pretty straight forward. So, what is t? t is this. I want to convert this to a list, let us say. I can say l is list of t, converted to a list. Now, I want to convert this list to a tuple for whatever reason. So, l1 is list of, sorry, t1. I want to convert the list that I, back to a tuple. I can say t1 is tuple of l. Remember that it is doing a value comparison. These two tuples are possibly different objects. But the, the essentially a tuple is, because it is a fixed immutable quantity. If these two quantities are equal, it means they contain the same objects. Finally, one more thing that I think is worth exploring and understanding. So, let me have an element a. I define a to be the list 1 comma 2, b to be say the list 3 comma 4. Now, let us say t is equal to a comma b, print t. Now, what do you think would happen if I did a dot append? So, now if I did a dot append 3, what do you think should happen? Obviously, not an error. A is now this. What do you think t should be? So, before we answer it, let us think about what is happening. t originally was set, was created as a comma b. a was 1 comma 2, b is 3 comma 4. Both are lists. I can now change a, because a is a list. I have access to it. I can say a dot append. I have now made a as 3. So, if you go back to the discussion I had in some detail yesterday about objects, names, namespaces. You will know that when I say t is equal to a comma b, it means that this t is essentially containing the first element is an object whose name currently is a. a is again a name of this object 1 comma 2, this list object. So, now that I have changed the list object itself by appending, the tuple should also change. Correct? Why? Because this name that I have assigned inside here refers to an object and that object has been changed. Therefore, if I print t, I should see the changed values. So, please keep this in mind. This is the same idea as we had yesterday. I am just trying to reinforce the concept by explaining it once again. The idea is essentially that of namespaces basically in python in every scope or many of the scopes, when you define a variable, that variable is essentially a binding or a connection or a mapping between an object and that name and that letter or the word or that variable name. This mapping is what is happening. So, when I say a, python looks to see whether there is a mapping for that name, finds the corresponding object and presents that. So, when I say t is equal to a plus a comma b, it looks for a, finds the object, sticks a reference to that object inside this tuple in the first place, sticks a reference to the object referred to by b in that place. So, now if I change a, independent of changing the tuple, instead of doing t of 0 dot append. So, if I did this for example, t of 0 dot append, obviously t will change, but so will a because they are both referring to the same object. So, this should clear many of your doubts if you have at some point saying, what is this doing? You should always think back and say, it is a name mapped to a object. So, with that done, let us move on to dictionaries, which are fundamental data structure that is available in Python, it is built in. So, so far we have dealt with sequences, which are strings and all of these had elements by which you can access sequentially the elements of that sequence. That is, I would start at 0, then I could say 1, 2, 3. I cannot have an element with just two numbers and be able to call. So, for example, if I say list containing 1 comma 2, so let us say a, a of 50 is meaningless. Neither can I get the value at a of 50 nor can I set the value, which basically means the way in which you access the indices, the access the quantities is very predetermined. If I have five elements, indices can only be between 0 to 4 or minus 1 through minus 4, correct? No or minus 5, no other is possible. However, very often you want to create something like a mapping, which says for this name or for this number, this is the value without the need to have something before it or something after it, without the need for a sequential kind of storage. This is how it is done using dictionaries. So, the way you create a dictionary, let us start with creating an empty dictionary. So, empty is open parent, open, let me clear the screen, open curly brace, close curly brace. Now, this creates an empty dictionary. Dictionaries are mutable, which means unlike tuples, I can change them. So, here is another example of a dictionary. It says, I do not know if the slide is readable, it says JPG, it is in quotes, it is a string colon jpeg image, py colon python script. So, let us try a simple example. So, in this line, I have not yet interpreted this line. The left hand side is the variable ext, this curly brace implies that I am starting to create a dictionary. Now, this is called a key. What is on the left of this colon? It is called a key. So, for the key jpeg, the value is image. For the key text, the value is text 5. So, once I create it, I close the curly bracket, hit return and now, let us print this and see what it is. So, it says txt text file jpg jpeg image. So, this is now, let us see what is the type of this. It is called a dict or a dictionary. Notice that there is no ordering of these keys. I entered the keys here as jpg first txt next, but when I print it, it comes out as text jpg. So, do not worry about any ordering with these keys. The point is, I now have a mechanism by which I can store keys with some values. So, how do I access these? So, let us look at this ext open bracket jpg close bracket. I will repeat this print ext open square bracket, give it the key name close square bracket and that is jpeg image. So, if you do not print it, you can actually see it is the jpeg image. So, essentially the syntax is dictionary open bracket key close bracket. This is how you access an element of this dictionary and notice that it does not have to be 0 minus 1. The name that you access it through is through the key name. So, for example, if I say ext of 0, it will say sorry key error. I do not know of any key called 0. So, if you want to create a key like that, you say we will come to that in a little while. So, is it clear ext of jpg is this, ext of txt is text file. How did I create this? That is how I created it. But now supposing I want to add a new element, how do I do it? Very easy. I can say ext of cpp is c plus plus 5. Now look at ext, cpp, jpg text file. Now, if I want to access the value of cpp, now let us say I want to change. I do not like this text file or I want to say I want to make it jpeg capital image or something like that. So, I say ext of jpg is equal to jpeg image. I just change the case of this i which is illustrating how you can change it. Now supposing I want to say in addition to these keys, I want to have 0, no problem. I will say ext of 0 equals a thing and now I can say ext of 0 that will also work. But ext of 1, no way that is not going to work because there is no key called 1. ext of jpeg continues to work, everything else continues to work as before. So, now I do not want this 0 because it is not an extension. I want to remove it. To remove it, you do del ext of 0 that is gone. So, you can basically create new keys, delete keys, key value pairs and you can assign to an existing key and that modifies the values. Now, the nice thing about dictionaries is I can check for container ship with respect to keys. So, I can say cpp in ext that is true. It will not check for values because it is basically going to look for keys not for values. When I say something is there something inside a dictionary, it is going to look for the keys and not the values. Just keep that in mind. Now, there are several methods. So, dict is an object. So, let us see what are the methods. So, you can see that there is this clear. Notice all the methods, there are several with these double underscores. Forget them. Consider all of these other ones here, ones below that clear. These are all the methods that we have access to that we can use. One is clear copy from keys get. Get is interesting. So, let us look at get. Get basically says dictionary dot get key and an optional value called a default. So, idea is this. Supposing I want to get something from a dictionary. So, if I say ext of f77, what will this give me? What should this give me? ext of f77, sorry, key error. So, it should give me a key error because there is no key called ext dot ext of f77 because ext has only cpp, jpg and txt. But supposing I say if there is no error, if there is an error, I want you to give me some default and not give me some error like this. Get will do that. So, if I say get f77 and give it a default value of say it would not give me an error, but it will return give me the default value. So, this is a convenient method. Let us look at the rest. There is something called has key. Using this you can check container ship essentially. There is something called items, iter items, iter keys, iter values, keys, pop, update and values. Out of these, two very commonly used methods are ext dot keys. This will give me a list of all of the keys that are available and this will give me a list of all values that are available in the same order. So, supposing I want to iterate over this dictionary, you look at the slides, you will see that here is the syntax. You can say for each in extension dot keys print each direct arrow extensions of each. So, let us try this simple example for key in ext dot keys print key comma ext. How do I get the value? That is all the values. I want to get specific value. Given a key, how do I get the value of that key? I just did it. So, give the brackets to the key. So, I say ext of key or if you want it in the format that has been given in the slides. Is this clear? However, you can be lazy and not have to do this at all because if you just did for key in ext, it will still work. By default, if you iterate over a dictionary, it will give you the keys. Is this clear? So, let us do some more. Now, we will have to concentrate on the shell. Just pay attention to the terminal. So, now, we have our ext. I now want very often you will find that you want to iterate over the elements. I showed you a simple example saying for key in ext print key ext very nice. Very often, you will find that you want not just the key, but in one shot you want the key and the item and the value. To do that, you can do for key comma value. By the way, though this key and value can be any names you choose. They are just variables in ext dot iter items. This is a special thing. So, for key comma value in ext dot iter items, print key. So, iter items basically iterates over every key value pair and returns them as a pair. So, let us see what it does. Actually, this one what it does is essentially does what items does. Items now returns a list of tuples. One for each key value pair. So, at the first iteration level, it will get cpp comma c plus plus 5. Now, this is a tuple. This side is also a tuple. So, what is done is tuple expansion. It will set these two to those two and set the key to cpp, the value to c plus plus 5. So, essentially it is doing the tuple expansion in a very convenient form for us. Is this clear? Therefore, this code works very conveniently. I do not have to now do ext of key. None of that needs to be done. So, let us explore a little more on ext dot. There is one more called ext dot pop. What pop, what does pop do for a list? It will remove the last element if you do not specify index. If not, it will remove the value at the specified index. So, for example, if I have l equals to 3, l dot pop will remove 3 from the list. Or I can say l dot pop, the index 0, it will pop out the first fellow or whichever you specify. Similarly, ext dot pop say cpp, but it also has an optional argument saying if the key is not found, return the default element. So, for example, now what is ext? It is cpp is gone. So, now if I say ext dot pop, cpp, it will give me an error. It will say key error, cpp is not found. But if I say no, no, if it is not there, you give me some some some other string or some other value. It gives me not found without giving error. It is kind of like get. That is it returns the same default instead of giving you an error. That is essentially what it does. So there are some other methods like there is update, which is a little more complicated. Essentially you can give a dictionary and other dictionary and ask this dictionary to update its key value pairs using that other dictionary. So, I would suggest that you experiment with these various methods of a dictionary on your own. By the way, so if you want to only iterate over the values of a dictionary, easy for v in ext dot values print v. This is only the values. So, if you want the values, you should do that. There is of course keys, which I have already shown you. So, only give me the keys. So, basically dictionaries are an extremely powerful, you may not realize how powerful they are. But very often they are the perfect solution for many problems. For example, if you are trying to create some kind of a simple internal database or you are trying to create a simple mapping internally for whatever programming purpose you need, a dictionary would be an ideal object to use. So, there is one important thing you need to remember when you are using dictionaries is that the keys generally avoid using mutable objects as keys. You can use anything as a key by the way. So, for example, you can use almost anything. Most anything can be used. So, I can say ext of 1 equals 2 1 3, no problem. This works. ext of 3.14 1592 equals 5. So, you can, the keys can be pretty much anything you want. You can even do this ext of 1 comma 2 equals also works. But do not try something like this ext of some mutable object. So, let us say d equals ext of d equals, it will tell you that dicts are unhashable. Therefore, I cannot do a mapping between this unhashable object and something else. In general, it is a good idea to not use something that is mutable as a dictionary key and very seldom do you actually need it. Another thing you could try, for example, is this is our ext. Now, let me define a function ext of f equals, that works. Similarly, I can do the reverse also works. So, now, if I say ext of f, tell me some function. ext of some function is a function and which I can call. So, it prints one. So, the advantage is I can store, I can use this for various purposes. So, supposing I want to, for this function that is the document. For this, this is the thing or you want to dispatch. If when this function is called, call that function. So, you say you have a list of strings and a list of corresponding function. Instead of maintaining two lists, you store them in a dictionary. So, there are a lot of patterns where dictionaries are like the ideal tool for your job. So, it is a good idea to master how to use dictionaries and use them effectively. So, we will give you some assignments over the course of the day to make sure you are able to use these dictionaries. So, with this I am covering finishing the dictionary part. There is a question about namespaces and someone wanting me to explain namespaces. So, maybe what I will do is, I will take this white board and explain to you on the white board what the. So, in python there is. So, you can imagine it like this. So, there are these objects, all the objects. So, for example, if I have a list of one, let us say I have 1.125 other objects and then I have some dictionary, some function. So, each of these is an object. So, if I take say this object, if I have a namespace, now my, if I call this A, this name A is now mapped to this object and it is kind of a many to one mapping. So, if I were now to write some python code and I say B equals A, essentially what happens is a new name B is created which maps to the same object contain. So, every time a variable is created some x is equal to 1. For example, let us and now if I say x equals 1.125, what happens is a new name x is created, I have a new name x which is bound to this object 1.125. So, and now if I create say an empty dictionary, this thing is mapped to that or if I define a function f, this happens and now if I say some f equals funk, essentially this f is a new mapping for the same object that is here. So, now let us say I have another function, I have some def g which accept some function and I do something with that function here and now if I call g with funk, what happens is in my interpreter here, when I call g of funk, this funk there is now a new binding, there is a new namespace here that is local inside this scope and this fellow will define a function which again points to the same object. So, essentially names in a namespace are bound to objects or they are mapped to some particular object. Therefore, if I did something like B is some tuple of say A comma B, then what happens inside this entire namespace here, A is a list is pointing to this, B is a dictionary that is pointing to this empty dictionary here and so now if I do A dot append 4, what will happen is t is essentially referring to the same object and therefore, we will see all of the changes. So, this is a high level understanding of namespaces is essentially if you want to summarize it in one line, names are bound to objects that is all and this is a central theme in Python, everywhere you see there is namespace means name bound to object, name bound to object. So, whenever you do these variable assignments, if you are calling a function you are passing do not get confused with pointers, these are not pointers, you are not passing pointers, there are no pointers in Python, there are only names that are bound to objects and new names can be constructed at will. Now, the only thing you may want to sort of an additional fact you may want to recall is when I do del of A, what that means is this name binding is broken. So, that means when I do del of A, this connection is lost, that A is no longer bound to that object. So, what should happen now to t? Will t be gone? No, because t has nothing to do with the name A, t has something to do with the object that A is referring to. Therefore, if I do del A, print t will still print will still give me 1, 2, 3 comma t. Again, because names are bound to objects and underneath they are all they are all using the same object that name has no sanctity, name can come, name can go, name can change, you do not care. The one thing you have to remember is if no one has a name for that object, the object is dead and it will be garbage collected, it will be destroyed essentially. Somebody who is unknown, unnamed, anything can happen to somebody like that and nobody will know. So, in python again, so there is a name that is bound, if that name goes out of scope. So, for example, I create a temporary variable some function here, after this function is executed that function variable is gone, that name space no longer exists, because that function is finished evaluating, anything defined in that function those names are all gone, but name space is no longer needed and the garbage collector will consume those objects. So, that is a brief elaboration of name spaces. I will get back to answering some questions before we move on to sets. Why having more precision in round 2.32? I already explained this. So, let us take simple example. This also depends on your python version. Different python versions seem to print things differently. So, let me take this one 3.1457. Now, when I print x, when I print it, it is essentially saying all of those other decimal places are useless. I am only printing the valid ones. Internally, it is doing something. When I actually type the value of it, it actually gives me the full decimal expansion. It is a 64 bit floating point number. As a result, it stores, it has that many bits, it is translating all of those bits into an equivalent decimal representation. You have to understand that with floating point numbers, many numbers cannot be represented exactly. There is no, for example, if I have a 2 bit number system, 2 bit number system, how many numbers can I express? If I have 2 bits, how many numbers can I express? Anyone can answer? How many integers, positive integers? Let us not worry about negative and positive. Positive non-zero integers, how many can I express? 2 to the power 2, correct? Each bit can be 1 or 0, 2 bits. So, I have 0, 1, 0, 1, 0, 1, 0, 1. So, there are 4 possibilities. I can encode every number, 4 numbers with this, one of which is 0. So, 0, 0 will be 0. Then you can have 1, 2 and 3. So, I can represent only 3 numbers with this. Now, supposing I have 8 bits, I am only looking at positive integers. So, I can represent 0 to 255. That is 2 to the power 8. Each bit has 2 possibilities, 8 such bits. So, I can have 2 to the power 8, possibility, combination. So, I can express 256 numbers, 0 to 255, I can express. If I have 64, I can express 2 to the power 64, which will be that many. But that is all. Remember that many numbers and all of these are represented in binary. So, if I take 1 by 7, what is 1 by 7? It is a never-ending fraction. So, I will have some positive fraction, some truncation that I will have to do beyond the point I cannot represent. Similarly, remember all of these numbers are binary. So, even if I say all numbers are going to be stored as 1 point, something, something, something, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 64 bits like that with some exponent. There are only some finite number of numbers that I can represent. Some numbers will not be, there is no exact representation in binary for that particular number. And therefore, there will be some small difference that you will see. What you should realize is that this difference exists is real, is there in your number system and you cannot run away from it. And when you print the value of such a number, if I take 1.0, it is fine, because 1 can be exactly represented. Why? What is 1? The bit 1, bit 1 with exponent 0 is 1, right. But if there are some numbers, for example, half, any power of 2 will be exactly represented. So, if I take 1.0 divided by 256, it is exact. There is no trailing 0, 0, 0, 0, 2, something, none of that. But what about 1 by 3? Gone. In this case, it keeps going. So, the difficulty is many numbers, you cannot, many fractional numbers, you cannot quite express exactly in the binary representation. Even if you think, oh, it is only two places. So, 2.3223, the binary representation in the floating point number system may not have an exact representation. And therefore, it will print you the nearest possible that it can do. So, when you get the answer, the answer may not be exactly what you have, which is why when you talk of floating point numbers, never do an exact comparison. For example, if you are expecting some value to be 0.3, do not ever do x is equal to 0.3. Instead, you should do if absolute magnitude of x minus 0.3 is less than 1 e to the minus whatever precision you determine. Actually, you do not need any case, I will just show a conditional. So, let us say x is, so you are doing some floating point calculation. For example, x is 0.1. So, I do for i in range 3, x plus equals 0.1. Even though I added 0.1 3 times to x, what was x? x was 0.1. I will repeat my calculations. x is 0.1. Now, I am simply doing for i in range 2, x plus equals 0.1. Correct? 3 times 0.1 should be what? 0.3. Now, is x equal to 0.3? No. So, as we will say in Tamil, yengio idikide. Something is wrong, something is not fitting. So, what do you do? The answer is you never compare. If I did this, what is a b s of x minus 0.3? It will be the absolute value of the difference. Look at the value, it is 10 to the minus 17. So, there is some small 1 last bit there which is 1 or some few bits towards the end of that 64 bit decimal place that is 1. So, when you do the difference, it is not 0. Therefore, it cannot be 0. When you do the 0.1, cannot exactly represented, neither is 0.3 exactly what represented. So, the difficulty is I cannot do a comparison. Therefore, if I say this is 1, this is less than minus 14, yes. So, if I am saying 0.3 to the other number, the difference is 10 to the minus 14, do I care that the difference is significant? No. Essentially, they are still pointed. Therefore, when you do numerical calculations, always be wary of any code that is doing something equals some value. Be very careful when you are doing something like that and always use something like this condition which again brings us back to answering your question of why is there more precision? There is no more precision. A floating point number in python is 64 bits. If you are looking for something called decimals where you are able to express them as a finite precision point that you control, there is a module in python called decimal which we will consider later on and we look at that later. The next question is how to perform addition of variable number of arguments with same function? I am sorry I do not understand the question. Are you saying sum of 1, 2 you cannot do? You must do make it a sum of 1, 2 in the bracket. It has to be a list or are you asking how do you create a function with variable number of arguments? Is that the question? Can VITV repeat their question on the chat session? Are you asking how do you create variable arguments? So, python allows for variable arguments. These are not quite in these slides, but I will show you the answer. So, supposing I define a function f, if I want a variable number of positional arguments, I can give it this function signature, def f star args colon. This star args essentially will take any additional positional parameters that you specify and store them in a sequence or a tuple called args. So, let us just try this. Let us just print args. Simple function. So, if I do f of 1, 2, what do you think args will be? Args will be a tuple 1, 2. What if I do 1, 2, so everything that is in this star args will be accepted. Now, supposing I say I want some specific arguments, I want to say x is something, I want y and I want anything else should come in star args that also can be done. So, notice that anything that was additional was simply stored as this tuple args. However, if I do not specify anything additional, that tuple will be empty and if I do not specify x or y, it will be an error saying at least two arguments should be there. Now, there is an extension to this variable keyword arguments that is also relatively straight forward. You can say star args if you want. If you do not want, forget it. Star star keyword args. Again, the name that keyword args is not anything sacrosanct. This name keyword args is up to you. It is just a variable. I forgot the colon. Print. So, what do you think keyword args will be? Any guesses? Args, when I guess star args, it was a tuple. What do you think keyword args will be? If I have to use some basic built-in Python data structure that allows you to say x is equal to 1, y is equal to 2, what would you use? So, think about my question and then I will get back to your answer. The next question is, I want to see whoever asks me that question, I want you to answer this question for me. When I do def f star star keyword args, what am I expecting? I am expecting that I can pass arbitrary keyword arguments. What is the keyword argument? Greed, name equals word. This is a keyword argument. I can call it as name equals Guido, greet equals hey. So, I am essentially using keyword argument. I am saying this is the name, that is the value. So, very good. So, someone has answered to me that star star keyword args is a dictionary. Absolutely correct. Therefore, I can continue answering the question. So, now I can say let us call it. Notice that keyword args is a dictionary. Now, what if I had called this as to be an error? Because this function takes no positional arguments. It takes only keyword arguments. So, now using this, you can write fairly sophisticated code, something that takes arbitrary arguments, something that takes arbitrary keyword arguments. You can also mix and match. So, for example, I can do this. So, once again I will repeat what I have been saying all of yesterday. If you want to experiment with some of these things, just type out on the interpreter, play around, you will understand what is going on. It is not very difficult. Since we are on the topic of this functions calling with arbitrary arguments. Now, supposing I have a list and I want to call a function with the elements of that list as positional arguments. So, let us say I have def func x comma y comma z, simple function. I want to call it with the elements of a list. That is somehow programmatically I was given three arguments which are in a list. So, I say my args is, I now do not want to do. So, how will I call this function now? I can do funk of args of 0, args of 1, args of 2. Very boring, right? That works. It is very boring, painful code. Instead I can just do this. What it will do is it will take that function, take the sequence, expand it out into the number of arguments that are necessary, return it to Python and call that function. Similarly, with keyword arguments. So, if I have a dictionary, I say you call it as star star. So, you know how to now write a function that takes arbitrary keyword arguments. I know that I can call a known function with certain keyword arguments using a dictionary. So, you can do both this way and that way. Now, this is fairly advanced. So, today we will try to do some elements of advanced Python programming as well. So, if you have even some crazy question like this, I will be able to answer. But pay a little careful attention to this, what has been done so far. And the secret of doing lot of these things is to experiment and think. There is no escape to do not blindly type something and then Google the answer. It is not a good idea. You should be able to think about it and say, that is why I am trying to stress on things like namespaces, trying to stress on experiment, look at the error messages. All of those things are very important for you to do. Is there any command line argument in IPython? I am not clear as to what your question is. Are you saying, are there command line arguments to IPython? Yes, certainly there are. The way to find out is the standard way for any Linux tool. You do IPython minus minus help. It will tell you a lot of information. How do you find out all the objects in the namespace? In IPython, it is easy. You just do who? It will tell you the interactive namespaces empty. However, if you want to know how to do it with pure Python, there are two dictionaries that are available typically called locals and globals. Now, this is pretty deep stuff. If you go down to globals and locals, you can start doing nasty things. If you do not know what you are doing, I will not help you. Be very careful when you start mucking around with stuff like this. The difficulty is you can start doing a bunch of things and if you are not careful, you can get into big trouble. Big trouble as in your files and all will not get deleted. Just your Python session may go for a toss. So, be careful when you start playing around with things like this. But basically, the globals and locals dictionary gives you access to the current namespace and what is defined in it. So, you can see a lot of internal stuff that is available when you do that. But generally, inside the iPython session, who, percentage who, all percentage commands are basically iPython special commands. They are not available in normal Python. There is also who's. So, for example, if I say x is 1 and I say percentage who, I will get x. If I say who's, it will give me more information. It will tell me variable type and information. Convenient. So, if I define say f, it tells me f and x are defined. Who's will tell me f is a function? Now, if I want to remove this binding, I already explained in my namespace slides. I did it on the terminal and I wrote it down in this sheet of paper. The way you remove a name bound to an object. So, first thing is how do you delete any object of namespace? Question is wrong. You cannot delete anything in Python. You only remove bindings to namespace in the namespace. So, you say del x, x is gone. So, if you want to remove some binding, you just say del, that variable name, that name is gone. The thing to remember is as soon as there are no names bound to that object, the garbage collector internally in Python will clear it up for you. You do not have to worry too much about it. So, I think I have answered all outstanding questions up to this point. We will resume after a break in half an hour.