This question already has answers here:
Difference between del, remove, and pop on lists
(14 answers)
Closed 3 years ago.
I'm learning python and I wanted to create some code which would take a list of lists, check if each row had a particular value for a given index number and if it did, delete the entire row. Now I intuitively decided to use del to delete the rows, but when I printed out the list with the removed values, I got the same list back. I added a counter to check if there were any rows which had the value to be removed and they did indeed exist. The problem I have is illustrated by the following code:
test_list=[1,2,3,4,5]
for element in test_list:
if element == 1:
del element
print (test_list)
Output
[1,2,3,4,5]
What is the function of del, if not to delete the element here?
Actually, del is doing nothing in your code. It's just deleting a local binding to the iteration variable (not to the list element, even though they point to the same object). This has no effect on the list, and anyway in the next iteration the variable will get assigned to the next value.
For the general case, if you wanted to delete an element in the list using del (and you didn't know where it's located), this is what you'd have to do:
delete_me = 1
for i in range(len(test_list)-1, -1, -1):
if test_list[i] == delete_me:
del test_list[i]
Notice how del works for lists, and the fact that we need to traverse the list in reverse to avoid problems when modifying a list at the same time we're iterating over it.
There is a simpler way, though - and that is not using del at all, but a list comprehension:
delete_me = 1
test_list = [x for x in test_list if x != delete_me]
del is removing the reference to the object element. Which is not the reference to the list element.
You are deleting a temporary variable named element which is created at each iteration on test_list.
If you want to remove an item from a list, use remove, or del list[index]
More here: https://www.tutorialspoint.com/python/list_remove.htm
How to remove an element from a list by index?
Is there a simple way to delete a list element by value?
The del keyword is used to delete objects. In Python everything is an object, so the del keyword can also be used to delete variables, lists, or parts of a list etc.
https://www.w3schools.com/python/ref_keyword_del.asp
Related
2 part question. Given the following code, my understanding is that i is a variable created within the loop function. As such, the changes have local scope and should not carry over ‘outside’ the function.
list = [3,4,5,6,7]
for element in list:
i = element * 100
print(i)
print(i)
printing i within the loop will produce the correct mathematical change. However, the second print(i) outside the loop returns 700. This technically refers to the correct reassignment of element 7 from the original list. So if changes in the loop only exist within the loop, why is it that this last one carried over ‘outside the loop’?
Furthermore, why is it that print(i) outside the loop returns the change to the last element? Why not the first element? Why not all of them? Is there some function I can call outside the loop to see the changes applied to elements 3,4,5,6?
Part 2 of my question - I know for a change to apply outside a loop, you should target the element via its index itself. Eg use for ‘element’ in range(len(list)). But can one also do this with enumerate? If so, how?
It seems that enumerate returns an object in the form of a tuple (it adds an ‘index counter’ as the first element, and keeps list as the 2nd element). And since tuples are immutable it would seem there is no way to effect a change on a global scope, is that correct?
For example, when I run the following code:
my_list = [1,2,100]
for xyz in enumerate(my_list):
xyz = 2 * xyz
print(xyz)
All it does it return to me the final element in my_list, with its index counter, concatenated to itself (‘doubled’). Eg (2,100) has become (2,100, 2,100). So is there no way to use enumerate to change elements within the original list?
To your first question, let's go through your misunderstandings one by one:
i is a variable created within the loop function
No. There is no "loop function" here. (User #0x5453 already mentioned this briefly in a comment.) The for-loop is just a language construct to facilitate iteration. Thus, i is just a variable that happens to be created, assigned, and re-assigned multiple times throughout the iteration of the for-loop.
the changes have local scope and should not carry over ‘outside’
See above. There is no other scope here. All those lines of code, starting with the list assignment and ending with that print(i) after the loop are all in the same scope. This should answer the following of your questions:
why is it that this last [change] carried over ‘outside the loop’?
why is it that print(i) outside the loop returns the change to the last element?
The variable i was re-assigned multiple times. In the last iteration of the for-loop, the value assigned to i was 7 * 100, i.e. 700. Then the loop ends, and nothing else happens to i, so it still holds the value 700.
To the second question:
for a change to apply outside a loop, you should target the element via its index itself
If you refer to the your list, then the loop has nothing to do with that at all. If you want to change an element of the list, yes, re-assignment only works by targeting the index of that element in the list:
my_list = [1, 2, 100]
my_list[2] = 420
print(my_list) # output: [1, 2, 420]
can one also do this with enumerate?
No, enumerate is something else entirely. Calling enumerate on my_list returns an iterator, which can then be used in a for-loop just like the original list can, but each element that iterator produces is (in its simplest form) a 2-tuple, where the second element is an element from my_list and the first element is the index of that element.
Try this:
for tup in enumerate(my_list):
print(tup[0], tup[1])
This will give you:
0 1
1 2
2 420
Since tuples are iterables, they support unpacking, which is why it is common to go for more readability and instead do this:
for idx, element in enumerate(my_list):
print(idx, element)
The output is the same.
Nothing about this changes my_list. All these operations do, is iterate over it in some way, which just produces elements from it one by one.
Now, you do this:
for xyz in enumerate(my_list):
xyz = 2 * xyz
Since xyz is just that index-element-tuple produced by enumerate, multiplying it by 2 just concatenates it with itself, as you correctly noted, creating a new tuple and re-assigning it to xyz. In the next iteration it gets overwritten again by what enumerate produces, then re-assigned again by you and so on. Again, none of that changes my_list, it just changes that xyz variable.
If I understood you correctly, you want to be able to mutate your list within a loop over its elements. While this can quickly lead to dangerous territory, a simple working example would be this:
for idx, element in enumerate(my_list):
my_list[idx] = 2 * element
print(my_list)
The output:
[2, 4, 840]
Now we actually change/re-assign specific elements in that list. As before, assignment only works with an index. But the index is what we get as the first element of the 2-tuple provided by enumerate in this case.
However, there are sometimes (arguably) more elegant ways to accomplish the same thing. For instance, we could use list comprehension to achieve the same result:
my_list = [element * 2 for element in my_list]
Here we overwrite my_list with a new one that we created through list comprehension iterating over the original list.
Hope this helps clear up some misconceptions.
l = [1,2,3,[4,5,6]]
I want
l = [1,2,3,[4,5,6,7]]
Now I want to add 7 in the list which is inside the list.
I applied the same logic as accessing [3][3]
l.insert("index","value") #syntax
l.insert([3][3],7)
But it isn't working. I couldn't solve it with append as well.
You want to add a 7 to the element at index 3 in l.
That is:
l[3].append(7)
you can do the following:
l[3].insert(3,7)
What's wrong with your approach? In the insert(index, value) method the index should be an integer. The [3][3] you are passing, is not an integer. Moreover, it is not even a valid value (meaning, you can't write eg x = [3][3].
The [i] after an object calls its __getitem__ method internally. So, what you are trying to do is
get the element 3 of the initial list
hope that what you get is a list
insert on position 3 of that list
So, you can do that
inner_list = mylist[3]
inner_list.insert(3, 7)
or, more compactly mylist[3].insert(3, 7)
If you want to insert at the last position, you could as well write mylist[3].append(7)
Here l[3][3] is an int. Ofcouse it will not work as there are no built-ins defined such as insert and append on int
While l[3] is of list type so it supports both of those functions
l[3].append(7) or l[3].insert(3,7)
Also lists are mutable type so making a change in inner list will be reflected in the outer list as well. Hope it helps
you can access to that 7 with:
l[3][3]
I am trying to append objects to the end of a list repeatedly, like so:
list1 = []
n = 3
for i in range(0, n):
list1 = list1.append([i])
But I get an error like: AttributeError: 'NoneType' object has no attribute 'append'. Is this because list1 starts off as an empty list? How do I fix this error?
This question is specifically about how to fix the problem and append to the list correctly. In the original code, the reported error occurs when using a loop because .append returns None the first time. For why None is returned (the underlying design decision), see Why do these list operations return None, rather than the resulting list?.
If you have an IndexError from trying to assign to an index just past the end of a list - that doesn't work; you need the .append method instead. For more information, see Why does this iterative list-growing code give IndexError: list assignment index out of range? How can I repeatedly add elements to a list?.
If you want to append the same value multiple times, see Python: Append item to list N times.
append actually changes the list. Also, it takes an item, not a list. Hence, all you need is
for i in range(n):
list1.append(i)
(By the way, note that you can use range(n), in this case.)
I assume your actual use is more complicated, but you may be able to use a list comprehension, which is more pythonic for this:
list1 = [i for i in range(n)]
Or, in this case, in Python 2.x range(n) in fact creates the list that you want already, although in Python 3.x, you need list(range(n)).
You don't need the assignment operator. append returns None.
append returns None, so at the second iteration you are calling method append of NoneType. Just remove the assignment:
for i in range(0, n):
list1.append([i])
Mikola has the right answer but a little more explanation. It will run the first time, but because append returns None, after the first iteration of the for loop, your assignment will cause list1 to equal None and therefore the error is thrown on the second iteration.
I personally prefer the + operator than append:
for i in range(0, n):
list1 += [[i]]
But this is creating a new list every time, so might not be the best if performance is critical.
Note that you also can use insert in order to put number into the required position within list:
initList = [1,2,3,4,5]
initList.insert(2, 10) # insert(pos, val) => initList = [1,2,10,3,4,5]
And also note that in python you can always get a list length using method len()
Like Mikola said, append() returns a void, so every iteration you're setting list1 to a nonetype because append is returning a nonetype. On the next iteration, list1 is null so you're trying to call the append method of a null. Nulls don't have methods, hence your error.
use my_list.append(...)
and do not use and other list to append as list are mutable.
This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 7 months ago.
I wanted to remove the word "hello" from this array, but I get the "index out of bounds" error. I checked the range of len(token); it was (0,5).
Here is the code:
token=['hi','hello','how','are','you']
stop='hello'
for i in range(len(token)):
if(token[i]==stop):
del(token[i])
You're getting an index out of bounds exception because you are deleting an item from an array you're iterating over.
After you delete that item, len(token) is 4, but your for loop is iterating 5 times (5 being returned from the initial len(token)).
There are two ways to solve this. The better way would be to simply call
token.remove(stop)
This way won't require iterating over the list, and will automatically remove the first item in the array with the value of stop.
From the documentation:
list.remove(x): Remove the first item from the list whose value is x. It is an error if there is no such item.
Given this information, you may want to check if the list contains the target element first to avoid throwing a ValueError:
if stop in token:
token.remove(stop)
If the element can exist multiple times in the list, utilizing a while loop will remove all instances of it:
while stop in token:
token.remove(stop)
If you need to iterate over the array for some reason, the other way would be to add a break after del(token[i]), like this:
for i in range(len(token)):
if(token[i]==stop):
del(token[i])
break
It's not recommended to delete a list element when iterating over this list. I'm not sure what you intend but you could create a new list without the stop
token=['hi','hello','how','are','you']
stop='hello'
new_tokens = []
for i in range(len(token)):
if(token[i]!=stop):
new_tokens.append(token[i])
or create a list with everything until stop is reached:
token=['hi','hello','how','are','you']
stop='hello'
new_tokens = []
for i in range(len(token)):
if(token[i]!=stop):
new_tokens.append(token[i])
else:
break
But never delete elements from a list you are iterating over because then the length of the list is modified but the range is not.
The reason you are getting this error is two fold:
you are using the anti pattern in Python of range(len(sequence)). You should use for index, value in enumerate(sequence)
You are mutating a sequence as you iterate across it.
The call to range(len(...)) is only evaluated once. So when you star it evaluates to 5. Once you remove your stop word the list no longer has 5 elements so token[4] results in an IndexError
Once you delete an item, there are no longer as many items in the list as there were originally, so i will get too big. Also, if you delete the item at index i, then the element that used to be at i+1 will now be at index i, but your code won't check it, since it goes ahead and increments i.
Use break statement after deleting because you are modifying the same list in which you are iterating.
for i in range(len(token)):
if(token[i]==stop):
del(token[i])
break
I don't disagree with any of the other answers, but the most Pythonic solution is to get rid of the loop entirely and replace it with one line:
token.remove(stop)
That will remove the first occurrence of 'hello' from the list.
I have an issue with clearing lists. In the current program, I have a method that clears a certain number of lists. This is rather inconvenient since during one part of the program where this method is used, it would be a lot more helpful if it only deleted the last element from the lists. Is there any way in which I can set index numbers as parameters to my method to solve this problem?
The code for the method
def clearLists(self):
del self.Ans[:]
del self.masses[:]
Whenever I want to use this method, I merely write self.ClearLists() and it deletes every element in a list.
you can use lst.pop() or del lst[-1]
pop() removes and returns the item, in case you don't want have a return use del
To delete the last element from the list just do this.
a = [1,2,3,4,5]
a = a[:-1]
#Output [1,2,3,4]
To delete the last element of the lists, you could use:
def deleteLast(self):
if self.Ans:
del self.Ans[-1]
if self.masses:
del self.masses[-1]