 Thank you, good morning, everyone. This talk was born out of curiosity because we are engineers, or we people, are curious human beings. And that's where it drives everything. And first of all, let me introduce myself. My name is Mike Jimenez. I'm a PhD student. You can contact me in any of social network using this handler. But by your means, try to talk to me afterwards. I'm super happy to discuss everything. And if you have crazy doubts about tiny things, yeah, we are going to talk. First of all, all the memes in this presentation are based on drag race. If you love Python and drag queens, please talk to me because we are going to have a lovely chat. It's June, so it's proud month. Be proud of your identities. We are a welcoming community, and we would like to be welcomed no matter who you are. With no further ado, let's begin with a talk. So do you know this sometimes standing in the shoulder of giants? So this talk is basically my take on the Brandon Rhodes audio taxi in a row. It's an amazing talk. He is an amazing speaker. By all means, check this talk. He is going to do it way better than I do. But I have different questions, so I ask different questions. So he says in this talk, the list is the most dangerous state of structures. And I said, OK, Brandon, I use lists every day. So what am I doing wrong? What is happening here? That was my reaction. So let's begin with the list constructor. 101, this should be easy. We have a list constructor and a literat. List constructor, we get an iterable, and we get us back a mutable object. And yeah, basically that's a list. We can say, OK, list, give me a, I will send you a string and I want an array or thing of things. And if I give the literal and other list, it could be a list. The empty spaces are not there because I am lazy. There's some meaning behind there. We will figure it out at the end of this talk. Well, at the beginning. So the Python fan tells us there should be one and preferably only one to do things. So which of the built-in constructs of the list would be better? Shout me, what do you think would be better? The first one, the first one and the second one. Go with performance. Second one. Second one. Second one, all agree? You're totally true. The second one is actually, well, I switch them. So the first one is way faster. Why is that? Because I think it's in the next slide. The built-in needs to call the functions. They need to build the function and they need to build us our list. So if you trace back what's happening when you call the list, it's going to call the built-in, load it in memory, and return us our lovely list. While the little, then two brackets knows how to do it. It's like, OK, you gave me two brackets. I know that's a list. Let's make the thing. But the take-off, if it's spytonic, it's faster. Everything that is built for our language, it would be faster because the things that you most use would be always faster. Would be better. Strange things that always bother new beginners. OK, why the list is return me? If I gave a list of strings, it will be returning me a list of character. Why is that? Because I said that the list gets an iterable and a string is an iterable. So it will iterate over every character and will return me back every character in a new position. While the list displayed, the literal would get the thing and store memory for a string. What's happening with the iterable, it's, oh, yeah. I have a list of arrays, and then I built in. I get an ID, remember what was behind this. So, yeah, let's say forward. Index in a list. OK, so we have two ways to access elements in a list. We can go count forward or backward, which makes very useful in some cases. Sometimes you want to get the prefix. Sometimes you want to get the suffix. So how can a list access every element of every position at a constant time? So then, OK, you can get me the 10th character in the same time, then you can get me the second character. How does the Python does it? So I know that the list starts at some position. Let's say it starts at the address 0. And I know that the character is one byte. Let's go with this assumption. I know this is not totally true. And if I want to get to the is character, I will multiply and I go straight forward to this address. But Python list doesn't have to have one type. In a list, I can have multiple types. So how is this possible? Is it a linked list? Is it a double linked list? How is this going to be a constant time access in a list? So let's go deeper. Let's see how the lovely people from the Python actually built the list. So first of all, if I see how a space is taking an empty list, it's zero. Cool. But if I see how much space is taking in memory, it's 64 bytes. What's happening? What's the list to something? What the hell? So what the documentation says? The documentation says there's not a linked list. It's a continuous array of reference of objects. What does this mean? This is the struct. We have the macro thing, the built things. We have a vector of pointers and a memory allocated. We want to know how much memory we have actually allocated. And this is the nice vector. So we have macro and test as what type of things we have. The size of the object. So here we have a list of three elements. And we have this link to list of addresses. So I don't care if the object that is in the list is a character, a list, wherever. It's only an address. It's a list of addresses. And then I have another parameter. It's like, OK, how much memory I have actually allocated. And here is fourth. So if I wanted to add a new object, I have still space, which is super cool. Oh, no, no, no, not so fast. So yeah, we have learned things. We know that the empty list has things, have created things. And if I create an empty list, and then I have a new element, or if I create a list with only one element, is this going to have the same size? What do you think? Is it? Yes? No, yes? OK, the actual answer is no. The size of the empty list with an element is 72 bytes. The size of a list where we have actually opened an element is 96. And why is that? Because that should be your reaction. Why is that? Let's start from the beginning. So an empty list is 64 bytes because we remember that we need to have this structure in place. And when we open an element, we have 72. So what's happening? When I create a list with one element, I said, OK, lovely built-in constructor. Could you please allocate to me memory for one element? So Liz said, OK, I'm going to allocate to you memory for one element. And this is what is happening behind the scenes. So when you open an element, there's some cleverness. I highlighted the cleverness because it's really clever. So it never allocates more things than you need. Like, if you don't need to allocate new memory by means, don't do it. And they have a growth pattern. So every time that you want to open things and you don't have enough space, it's going to allocate more memory. Because if you want to open new things and you run out of memory every time, it's going to be crazy. You need to copy every element to a new position every time you do an event. So you don't want that. So you grow. You first start with a zero, then you multiply by four. Well, it's actually a smaller allocation. What's happening? Let's say with picture, I'm a graphic art person. So when I open an element, I allocate the memory for four elements, even the only one is there. So that's why it's different. Let's go through the least dangers. There's a lot of dangers no one is safe here. To one line of vendors, I find this very often that there's some mistake that I actually do as well. There are some operations that seem and it's going to take one second. It's going to be a constant time. But it's actually not. Like, happening an element, it's going to be ODN in some cases where we have seen the example then. If I run out of memory, I need to allocate new memory. I need to copy all the elements. And let's start with the basic one, the in element. Inim is really crazy, because you think, OK, if an element is in a list, it's one liner, it's OK. So what's happening? For example, if I said, OK, is nine in the list? If it's the first element, yeah, it is. Party, it's great. But what happens if it's not in the list at all, like the worst case scenario? It goes through the first element. It's not the first element. So we go to the second element. It's not the second element. We go through the third element. It's neither the third element. So we need to go through all elements in the list in order to figure it out. OK, this element is actually not in the list. So that's a danger. The insert, insert is also a danger one. So let's go through the worst example. Like, I want to insert two at the beginning of this list, which actually should be 1, 3, 4. Pardon my mistake. So the thing that it's going to do is push back everything. So they need to move things around in order to make space for the new element. And then I insert the element in the proper position. So it's only one line. It's going to be on. It's going to take a lot of time. We are looking at small examples, but it's going to be really dangerous if we are handling huge lists. So the slicing operator. The slicing operator for me is the worst at all of all the offenders because a slicing operator makes a copy of the list, which is bad. It's amazing for accessing faster things, but it's bad because we don't know exactly what we are doing. If we don't know what we are doing, it's going to be tricky. So what does the slice does? They find the positions that you want to slice, takes the higher, the lower, and creates a new list. It's basically you are creating a copy of the list that you have from the scratch, which is bad. Do you remember how many operations do we need to do where we were creating elements in a list? So these are examples of how the slicing operator works. You set the lower bound, the upper bound, and it will return you the positions. So keep in mind always that you can go forward and backward. You can get. So yeah, the second line is what the actual, the commented line is what the actual compiler does for you. Like we don't need to put where does the list shoot them. So if I say the slice to the end, it will replace it. And it will replace also the stride. We can move into steps. And there's cool things like I can reverse a list. If I tell it, hey, I want all the list, but I want to step to be on the other content for badware. And we also have the reverse operation in the list, which is in place. We don't need to do a copy. So think if you need a performance, you might don't want to do the slicing operator, you might want to do the reverse one. And okay, so cool thing. If you don't have a list, if your list is actually a matrix, you will have this list of reference will be a new list. So if you use the slicing operator to copy things, you are actually not, you're going to get a new list, but the elements of the list could be a reference of the previous list. So you actually don't have copy, but Python people knows it better and you have deep copy. So if you want to have an actual copy of a matrix, you just call it copy and it does it for you. Removing flavors. There's different ways of removing things in a list. So I'm going to straightforward to go to the example. It's way better. So if you want to remove the element, the number one is going to look for the first occurrence of the element and it's going to take it away. Again, it's like the in operator. If the element is at the beginning, we are so, it's great because it's going to take no time. It's at the end. It's going to be really bad. And it found, I did a mistake. Yeah. So what we want to remove is the element that the position is. So it looks for the two and takes the two to recycling. And again, it needs to push elements so the list stays in the correct way. Another way is to remove. We can remove the first matching element with remove and we can delete the element of an index. So deal has a strange indexes I guess, but this is still Python. It's Python three. So, yeah. And pop. Okay, pop is not actually dangerous because if you want to pop the last element of the list, it's going to be super fast. The problem is then we are not so clever and sometimes you want to pop some parts of the list which is going to be problematic. And yeah, going to go to a sorted list and I will finish there. So my child doesn't kill me. Sorting things. Which algorithm do you think then sorting is implemented in Python? Sort? Sort. Yeah, you did your homework. Yeah, team sort. It's super cool to have our own algorithm. So yeah, we have the sort and the sort that you can sort in place. You can sort and returns a new element. Again, remember if you are sorting and returning a new list, you are getting a copy of the list. So this is going to be responsive and sorted way faster. And the sorting algorithm is actually how the audience knows team sort. It's in a natural, it's a mix between merge sort and insert sort goes through all the list, tries to figure out where then this thing, this natural runs like places where the array is already sorted. And then makes a mix of merge and insert sort which is makes n log n if I'm not mistaken. I can only finish. So I have time for questions. Yeah, great. So I talk super fast, isn't it? Yeah, great. So yeah, we have some time for questions, please. Yeah, sorry. Okay. So yeah, we can have a couple of questions. Yeah. I'm not sure whether this microphone. Yeah, it's working. Again, the question. So any question? Yeah, we have one here. Sorry, I tend to talk too fast. Thanks very much. That was really fascinating. Can you go back a few slides? Yeah, of course. Where you had the deletes in the, just a, I think one, there we are. Okay. One forward from there. No, one next slide. Next? That one. Okay, good. Can you explain why there is this apparently so different syntax for deleting an item from a list when all the other operations seem to be methods on the list? I think this is very unsettling for people who encounter it. Why is there such a completely different looking syntax? I honestly have no clue, but I know that we have to see Python developers here, so we can ask them. But yeah, actually, sometimes it's different. It's difficult because the deal, it's not following the proper Python syntax. So actually it's the one that it's always forgotten because it's like, okay, this must not be Python, but it actually is. I don't know why they decided to do it that way, but yeah. There's always a reason. And that's reason. We can ask later. Maybe we can find someone who can give an answer. Is there more questions somewhere? Okay, so it seems that's all. That's all. Thank you very much again. Thank you. Yeah.