Tuples in For Loops - Python [duplicate] - python

This question already has answers here:
How to change values in a tuple?
(17 answers)
Closed 1 year ago.
I want to subtract 1 from every digit in a tuple using for loop in Python.
I don't understand why my code is returning the original tuple instead of the desired one. Here is the code:
tuple = (3, 2)
for i in tuple:
i -= 1
print(tuple)
Any idea ?

Tuples are immutable objects, that is, you cannot change the elements of the tuple once it is created, if you do want to change them it would be better to use a list.
a = [3, 2]
for i in a:
i -= 1
print(a)
Which gives an output:
[3, 2]
Why didn't it work, even though lists are mutable? And also, why doesn't your original code produce some kind of error, if tuples are really immutable? Well, this becomes more obvious if you write your for each style loop as a simple for:
for index in range(len(a)):
i = a[index]
i -= 1
print(a)
This code is just a more verbose version of your original example, but now the problem is clear - the code never actually changes the elements of the original list. Instead, each iteration of the for loop creates a new variable, i, which takes its value from the correspondinglist element. i -= 1 changes i, not a[index].
Incidentally, that is why there is no error in your original code, even though tuples are supposed to be immutable - the code simply doesn't try to mutate the original tuple at all.
A working example with a list would be something like:
a = [3, 2]
for index in range(len(a)):
a[index] -= 1
print(a)
which can be made more concise in the end by writing:
a = [3, 2]
a = [i - 1 for i in a]
print(a)
As an aside, if you really must take tuples as input and produce tuples as output, you can convert between tuples and lists using the list and tuple functions. This is also why you shouldn't use tuple as your variable name! Doing so will mean that you can't use that tuple function in the same scope as your tuple variable, making things very difficult and potentially confusing for you.

tuple is immutable
my_tuple = (1,2,3)
my_tuple [0] = 3
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

A couple of things going on. A tuple is immutable and you're assigning the value (3, 2) to the type tuple .
tup = (3, 2)
for i in tup:
i -= 1
print(tup)
Outputs:
(3, 2)
However you could do a list comprehension and cast it to tuple to get the expected result.
tup = (3,2)
tup = tuple([i - 1 for i in tup])
print(tup)
Outputs:
(2, 1)

Tuple is immutable.
try this, i think it will help you.
my_tuple = (3, 2)
new_list = []
for i in my_tuple:
i -= 1
new_list.append(i)
new_tuple = tuple(new_list)
print(new_tuple)

A brief introduction to python data structures should help you out here. Here's the gist
tuples are immutable i.e once created you cannot change the contents, you'll need to create a new one - you cannot modify the contents inplace similar to how strings work in python.
list makes sense but in your case it will still not work because you need to update the contents of the list when you do this:
tuple = (3, 2)
for i in tuple:
i -= 1
print(tuple)
you are basically extracting the contents from the tuple and modifying the value but not storing it anywhere. Even if you use a list like this:
list = [3,2]
for i in list:
i -= 1
print(list)
this will still not work as you are modifying a list item (a primitive type - int, string,etc.) which creates a new item but as it's not being stored it gets lost, when you print the list - it remains the same.
What we can do is modify the list as its mutable at runtime and update the contents like this:
list = [3, 2]
for idx, item in enumerate(list):
list[idx] = item - 1
print(list)

I think tuple is a bad variable name for a tuple because it shadows the tuple of Python
Issue is the values assigned to i are integers and integers themselves are not mutable. So even if i changes, the value in tuple does not. In other words, even though i points to the same object as the integer in tuple, when you do in place subtraction, a new integer is formed and i now points to that, different than what tuple has.
However, if you were to put a mutable object and do similar things:
tup = ([1, 2, 3], [4, -12])
for i in tup:
i[1] = 999
print(tup)
You get
([1, 999, 3], [4, 999])

Related

What's the difference between list.append(a) vs. list = list + [i] (for the purposes of recursion)? [duplicate]

Why do these two operations (append() resp. +) give different results?
>>> c = [1, 2, 3]
>>> c
[1, 2, 3]
>>> c += c
>>> c
[1, 2, 3, 1, 2, 3]
>>> c = [1, 2, 3]
>>> c.append(c)
>>> c
[1, 2, 3, [...]]
>>>
In the last case there's actually an infinite recursion. c[-1] and c are the same. Why is it different with the + operation?
To explain "why":
The + operation adds the array elements to the original array. The array.append operation inserts the array (or any object) into the end of the original array, which results in a reference to self in that spot (hence the infinite recursion in your case with lists, though with arrays, you'd receive a type error).
The difference here is that the + operation acts specific when you add an array (it's overloaded like others, see this chapter on sequences) by concatenating the element. The append-method however does literally what you ask: append the object on the right-hand side that you give it (the array or any other object), instead of taking its elements.
An alternative
Use extend() if you want to use a function that acts similar to the + operator (as others have shown here as well). It's not wise to do the opposite: to try to mimic append with the + operator for lists (see my earlier link on why). More on lists below:
Lists
[edit] Several commenters have suggested that the question is about lists and not about arrays. The question has changed, though I should've included this earlier.
Most of the above about arrays also applies to lists:
The + operator concatenates two lists together. The operator will return a new list object.
List.append does not append one list with another, but appends a single object (which here is a list) at the end of your current list. Adding c to itself, therefore, leads to infinite recursion.
As with arrays, you can use List.extend to add extend a list with another list (or iterable). This will change your current list in situ, as opposed to +, which returns a new list.
Little history
For fun, a little history: the birth of the array module in Python in February 1993. it might surprise you, but arrays were added way after sequences and lists came into existence.
The concatenation operator + is a binary infix operator which, when applied to lists, returns a new list containing all the elements of each of its two operands. The list.append() method is a mutator on list which appends its single object argument (in your specific example the list c) to the subject list. In your example this results in c appending a reference to itself (hence the infinite recursion).
An alternative to '+' concatenation
The list.extend() method is also a mutator method which concatenates its sequence argument with the subject list. Specifically, it appends each of the elements of sequence in iteration order.
An aside
Being an operator, + returns the result of the expression as a new value. Being a non-chaining mutator method, list.extend() modifies the subject list in-place and returns nothing.
Arrays
I've added this due to the potential confusion which the Abel's answer above may cause by mixing the discussion of lists, sequences and arrays.
Arrays were added to Python after sequences and lists, as a more efficient way of storing arrays of integral data types. Do not confuse arrays with lists. They are not the same.
From the array docs:
Arrays are sequence types and behave very much like lists, except that the type of objects stored in them is constrained. The type is specified at object creation time by using a type code, which is a single character.
append is appending an element to a list. if you want to extend the list with the new list you need to use extend.
>>> c = [1, 2, 3]
>>> c.extend(c)
>>> c
[1, 2, 3, 1, 2, 3]
Python lists are heterogeneous that is the elements in the same list can be any type of object. The expression: c.append(c) appends the object c what ever it may be to the list. In the case it makes the list itself a member of the list.
The expression c += c adds two lists together and assigns the result to the variable c. The overloaded + operator is defined on lists to create a new list whose contents are the elements in the first list and the elements in the second list.
So these are really just different expressions used to do different things by design.
The method you're looking for is extend(). From the Python documentation:
list.append(x)
Add an item to the end of the list; equivalent to a[len(a):] = [x].
list.extend(L)
Extend the list by appending all the items in the given list; equivalent to a[len(a):] = L.
list.insert(i, x)
Insert an item at a given position. The first argument is the index of the element before which to insert, so a.insert(0, x) inserts at the front of the list, and a.insert(len(a), x) is equivalent to a.append(x).
you should use extend()
>>> c=[1,2,3]
>>> c.extend(c)
>>> c
[1, 2, 3, 1, 2, 3]
other info: append vs. extend
See the documentation:
list.append(x)
Add an item to the end of the list; equivalent to a[len(a):] = [x].
list.extend(L)
- Extend the list by appending all the items in the given list;
equivalent to a[len(a):] = L.
c.append(c) "appends" c to itself as an element. Since a list is a reference type, this creates a recursive data structure.
c += c is equivalent to extend(c), which appends the elements of c to c.

choosing a random number from a tuple + some numbers

I have a tuple of numbers, and I want to choose a random number from my tuple in addition with a certain number. For example:
my_tuple = (1,2,3)
and I have the number 4. I want to choose a random number from the numbers 1,2,3,4 (without changing the tuple of course).
I tried:
my_tp = (1, 2, 3)
a = random.choice(list(my_tp).append(4))
print(a)
I'm new to python. I tried converting the tuple to a list, and then performing the random function.
The code above didn't work. Got the error
object of type 'NoneType' has no len()
Would love some help.
list.append returns none
Once converting to a list as you have done, appending will modify that list but return none so that is the source of your error.
To get round that you can either convert the tuple to a list then append 4 to it, then use random.choice, or in just one step, you can concatenate a list of [4] with the + operand.
This approach is much simpler:
import random
my_tuple = (1,2,3)
random.choice(list(my_tuple) + [4])
Hope this helps and clears some things up! :)
Update:
If you want to just randomly select from the tuple without the last item, then just slice the list with the normal syntax:
random.choice(list(my_tuple)[:-1])
The method list.append alters the provided list and returns None, which explains the exception you got. To get the desired result, you can implicitly use the tuple.__add__ method, which will return a new tuple.
values = (1, 2, 3)
random.choice(values + (4,))
If you want to remove values in a concise-ish fashion, using a set might be appropriate.
values = {1, 2, 3}
random.choice(list(values - {3}))
You can try:
my_tuple = (1,2,3)
random.choice((*my_tuple, 4))
Where (*my_tuple, 4) creates a new tuple with the unpacked content of my_tuple and 4.

Python: TypeError: 'int' object is not iterable(Think Python 10.3)

I trying to solve Think Python exercise 10.3
Write a function that takes a list of numbers and returns the cumulative sum; that is, a new list where the ith element is the sum of the first i + 1 elements from the original list. For example, the cumulative sum of [1, 2, 3] is [1, 3, 6].
I get a TypeError with this code:
def culm_sum(num):
res= []
a = 0
for i in num:
a += i
res += a
return res
When I call culm_sum([1, 2, 3]) I get
TypeError: 'int' object is not iterable
Thank you!
The code you are using to append to your list is incorrect:
res += a
Instead do
res.append(a)
What's wrong with res += a? Python expects a to be iterable and behind the scenes tries to do the equivalent of:
for item in a:
res.append(a)
But since a is not iterable, so you get a TypeError.
Note I initially thought your error was in for i in num: because your variable was poorly named. It sounds like it's a single integer. Since it is a list of numbers at least make it plural (nums) so that readers of your code are not confused. (The reader you will usually be helping is future you.)
What you are trying to do this is extend your list with an int, which is not iterable, and hence the error. You need to add the element to the list using the append method :
res.append(a)
Or, do this, the correct way to extend :
res += [a]

How does Python iterate a for loop?

I tried the following code on Python, and this is what I got:
It seems like for many changes I try to make to the iterables by changing elem, it doesn't work.
lis = [1,2,3,4,5]
for elem in lis:
elem = 3
print lis
[1, 2, 3, 4, 5]
However if the iterables are objects with its own methods (like a list), they can be modified in a for loop.
lis = [[1],[2]]
for elem in lis:
elem.append(8)
print lis
[[1, 8], [2, 8]]
In the for loop what exactly is the 'elem' term? Thanks in advance!
The reason that this doesn't work is because you're misunderstanding what elem is. It's not the object itself, and it's not even correct to call it a "variable".
It's a name, kind of like a label, that points to the object. If you just directly assign over it, you're just overwriting the name to point at something else. But, you still have the original reference to the list, so assigning a different value over elem doesn't modify lis itself.
Now, in this case, since all of the objects that elem points to are integers, you can't even change them at all - because integers (and many other types, like strings or tuples) are immutable. That means, simply put, that once the object has been created it cannot be modified. It has nothing to do with whether they "have methods" or not (all Python objects have methods, integers included), but on whether or not they are immutable.
Some objects, however, are mutable, meaning that they can be changed. Lists are examples of such objects. In your second example, elem is a name that references the list objects contained within lis, which themselves are mutable. That is why modifying them in-place (using .append(), or .remove(), etc) works fine.
The elem variable in your for loop is a reference to the current object on each iteration. Changing it won't do anything; it will just change the value of the variable elem and that's going to be changed the next time through the loop anyway. To actually change the value of the element in the list, you need a reference to the list and the index of the element to be changed, and you don't have the latter.
So what you want to do is something like this:
for index, elem in enumerate(lis):
lis[index] = 3
This way you have elem for the element's value and index for the position in the list. It saves you from writing lis[index] constantly to get values, but you must still do so to change elements.
You can also do:
for index in xrange(len(lis)):
lis[index] = 3
However, in most situations this is considered un-Pythonic (among other things, what happens if the list gets longer or shorter while it's being iterated)?
Here, you are actually modifying the list object in your second example. In the first example, you are not modifying the number, you are replacing it. This can be a complicated nuance for new users of Python.
Check this out:
>>> x = 1
>>> id(x)
4351668456
>>> x = 2
>>> id(x)
4351668432
id returns the identifier of the object. As you can see above, the object of x changes both of these times.
>>> y = [1]
>>> id(y)
4353094216
>>> y.append(2)
>>> id(y)
4353094216
Here, I modify the list, so the list is still the original object y.
So, all this means that when you are doing elem = 3, it's not modifying it, it is replacing it. And by now, it's not associated with the list anymore.
This is one of the ways you could do what you are trying to do. This grabs the index and then modifies the list, not the number.
lis = [1,2,3,4,5]
for idx, elem in enumerate(lis):
lis[idx] = 3
print lis
[1, 2, 3, 4, 5]
When you assign a new value to the name elem, you just change the local binding in the for loop. If you want to change the values stored in lis, use map or a list comprehension, like this:
lis = [3 for elem in lis]
You can, however, modify the attributes of elem (or call methods that do so), just like you can on any other value.
In your first example you are trying to modify an integer, and it's inmutable (as strings are).
Python variables should be seen as labels pointing to an object. When you iterate over a list of inmutables, elem points to an inmutable object, not to that position in the list, so you can't modify the original list.
In the second case, elem point to an object that can be modified, so you see the original list changed.
It depends on what the type() of elem is.
In your first case each elem is an int object and it does work to change it. You are changing a temporary object when you say: elem = 3, not the item in the list itself.
In the second case each elem is a list object.

Python List concepts [duplicate]

This question already has answers here:
Why do these list operations (methods: clear / extend / reverse / append / sort / remove) return None, rather than the resulting list?
(6 answers)
Closed 7 years ago.
I am new to python programming
why this assignment value to k is giving 'None' value
> >>> l=[2,3,4]
> >>> k=l.append(14)
> >>> print k
None
> >>> print l
[2, 3, 4, 14]
in above example List,I append the 14 value to list and then assigned to k but k is printing None please tell me the reason why its printing None instead of appended list?
Thanks
mukthyar
append changes the current list and doesn't return anything. Use:
k = l + [14]
or
k = l[:] # Copy list
k.append(14)
Most methods in Python which mutate their instance (.append(), .sort(), et al.) do not return a copy of the object. Thus l.append(X) does actually return "None" just as l.sort() would.
You'd probably want to use something more like:
l.append(14)
k = l[-1]
In python default return type is None so if your function is not return any value then you will get the None from that function. There are different functions for the object. Some functions are perform on same object and others are return the modified copy. For example list.sort will change the original list while sorted will return the new sorted list without changing the original one. So append is working on object so it will change the object value instead of returning new modified copy.
Hope this will make your view clear about append method.
What you are seeing is expected - the list.append method does not return the modified list. If you take a look at the relevant section of the Python tutorial, you'll notice that methods which return useful values are documented as such.
Working in the interactive interpreter, you can tell that the expression yields None by the lack of output:
>>> l = [1, 2, 3]
>>> l.append(14)
>>>
If (theoretically) list.append returned the list, you would see the following instead:
>>> l = [1, 2, 3]
>>> l.append(14)
[1, 2, 3, 14]
>>>
Using the interactive interpreter this way can save you from printing every value.
from python document
list.append(x)
Add an item to the end of the list; equivalent to a[len(a):] = [x].
in simple word append function returns nothing but None
suggested reading

Categories