This question already has answers here:
Is it safe to rely on Python function arguments evaluation order? [duplicate]
(2 answers)
How to prove that parameter evaluation is "left to right" in Python?
(6 answers)
Order of execution of expressions in Python
(3 answers)
Does python have an arguments processing order well defined?
(2 answers)
Closed 5 years ago.
I would like to understand the way Python evaluates function calls inside print statements or, more particulary, what does the call for
next(some_iter) return? A mutable reference to the element in the next position or just a copy of the element in the next position when some_iter was last evaluated?
The following code:
def foo(val, arr=set()):
arr.add(val)
return arr
print(foo(1))
print(foo(2))
print(foo(1), foo(3), foo(0))
Returns the output:
{1}
{1, 2}
{0, 1, 2, 3} {0, 1, 2, 3} {0, 1, 2, 3}
Python calls the function three times, holding what seems to be a reference to arr, then, since sets are mutable, the output is as can be seen above. foo(1) return value was not saved, that is {1, 2} when it is called in order of the print statement.
However
lst = [1, 2, 3, 4]
def bar(a):
a = lst
a[0] = 17
return a
x = iter(lst)
y = iter(lst)
print(next(x), bar(lst), next(y), next(x))
print(lst)
Would print
1 [17, 2, 3, 4] 17 3
[17, 2, 3, 4]
I would have expected
17 [17, 2, 3, 4] 17 3
[17, 2, 3, 4]
That is for next to hold a reference to the first element of lst, which would later be changed to 17, and for that reference to be printed as 17 eventually, but it is computed first returning 1.
Why does it not happen? In what way is the next() or iters different?
Related
This question already has answers here:
Why can't I iterate twice over the same iterator? How can I "reset" the iterator or reuse the data?
(5 answers)
Closed 3 years ago.
I'm learning Python and while doing some coding to practice I duplicated one line and the result was unexpected.
def myfunc(x):
return x*2
myList = [1,2,3,4,5]
newList = map(myfunc, myList)
print('Using myfunc on the original list: ',myList,' results in: ',list(newList))
print('Using myfunc on the original list: ',myList,' results in: ',list(newList))
I would expect to see the same result twice, but I've got this:
Using myfunc on the original list: [1, 2, 3, 4, 5] results in: [2, 4, 6, 8, 10]
Using myfunc on the original list: [1, 2, 3, 4, 5] results in: []
Why does this happen and how to avoid it?
newList is not a list. It's a generator that yields data on demand and will be exhausted after you retrieve all the data it holds with list(newList). So, when you call list(newList) again, there's no more data to put in the list, so it remains empty.
This question already has answers here:
How do I get the last element of a list?
(25 answers)
Cycle through list starting at a certain element
(7 answers)
Closed 4 years ago.
list1 = [1,2,3,4]
If I have list1 as shown above, the index of the last value is 3, but is there a way that if I say list1[4], it would become list1[0]?
You can you modulo math like:
Code:
list1 = [1, 2, 3, 4]
print(list1[4 % len(list1)])
Results:
1
In the situation you described, I myself use the method #StephenRauch suggested. But given that you added cycle as a tag, you might want to know there exists such a thing as itertools.cycle.
It returns an iterator for you to loop forever over an iterable in a cyclic manner. I don't know your original problem, but you might find it useful.
import itertools
for i in itertools.cycle([1, 2, 3]):
# Do something
# 1, 2, 3, 1, 2, 3, 1, 2, 3, ...
Be careful with the exit conditions though, you might find yourself in an endless loop.
You could implement your own class that does this.
class CyclicList(list):
def __getitem__(self, index):
index = index % len(self) if isinstance(index, int) else index
return super().__getitem__(index)
cyclic_list = CyclicList([1, 2, 3, 4])
cyclic_list[4] # 1
In particular this will preserve all other behaviours of list such as slicing.
This question already has answers here:
How do I concatenate two lists in Python?
(31 answers)
Closed 5 years ago.
This sounds like a super easy question, so I'm surprised that searching didn't yield any results: I want to initialize a list of constants and extend it with a list from another source.
This works:
remoteList = [2, 3, 4]
myList = [0,1]
myList.extend(remoteList)
Which means it gives the expected results:
myList
[0, 1, 2, 3, 4]
However, doing the list initialization in one line doesn't work, myList is left undefined:
remoteList = [2, 3, 4]
myList = [0,1].extend(remoteList)
Is there a way to initialize the list and extend it with another list (in a pythonic way) in one line? Why doesn't my one line example work, or at least produce some sort of list?
You can use unpacking inside the list literal
myList = [0, 1, *remoteList]
This is part of the unpacking generalizations made available in Python 3.5
Are not you just asking about the + list concatenation operation:
In [1]: remoteList = [2, 3, 4]
In [2]: myList = [0, 1] + remoteList
In [3]: myList
Out[3]: [0, 1, 2, 3, 4]
Works for both Python 2 and 3.
There are some slight differences between "extend" and "plus":
Concatenating two lists - difference between '+=' and extend()
a = [2,3,4]
b = [1,2] + a # will add the other list
print( b)
Output:
[1, 2, 2, 3, 4]
This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Why does foo.append(bar) affect all elements in a list of lists?
(3 answers)
Closed 6 years ago.
I've encountered what I think is odd behaviour for the append() function, and I've managed to duplicate it in the following simplified code:
plugh1 = []
plugh2 = []
n = 0
while n <= 4:
plugh1.append(n)
plugh2.append(plugh1)
n = n+1
print plugh1
print plugh2
I would expect this code to result in:
plugh1 = [1, 2, 3, 4]
plugh2 = [[1], [1, 2], [1, 2, 3, ], [1, 2, 3, 4]]
but the actual result is:
plugh1 = [1, 2, 3, 4]
plugh2 = [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]
As the loop runs, each time all array elements are replaced with the value of plugh1.
There is a similar question on SO but the solution seems related to nesting functions and defining a variable outside of those calls. This is much simpler I think. What am I missing?
When you do
plugh2.append(plugh1)
you are actually appending a reference to the first list, not the list as it currently is. Therefore the next time you do
plugh1.append(n)
you are changing the contents inside plugh2, as well.
You could copy the list like so, so that it doesn't change afterwards.
plugh2.append(plugh1[:])
The reason this occurs is that you are not copying the list itself, but only the reference to the list. Try running:
print(pligh2[0] is pligh2[1])
#: True
Each element in the list "is" every other element because they are all the same objects.
If you want to copy this lists themselves, try:
plugh2.append(plugh1[:])
# or
plugh2.append(plugh1.copy())
This:
plugh2.append(plugh1)
Appends a reference to plugh1, not a copy. This means future updates are reflected in plugh2. If you need a copy, see here: https://docs.python.org/2/library/copy.html
This question already has answers here:
Python: pop from empty list
(5 answers)
Closed 3 years ago.
N=8
f,g=4,7
indexList = range(N)
print indexList
print f, g
indexList.pop(f)
indexList.pop(g)
In this code I am getting an error stating that the pop index of g in indexList is out of range.
Here is the output:
[0, 1, 2, 3, 4, 5, 6, 7]
4 7
Traceback (most recent call last):
indexList.pop(g)
IndexError: pop index out of range
I don't understand, g has a value of 7, the list contains 7 values, why is it not able to return me the 7 in the list?
To get the final value of a list pop'ed, you can do it this way:
>>> l=range(8)
>>> l
[0, 1, 2, 3, 4, 5, 6, 7]
>>> l.pop(4) # item at index 4
4
>>> l
[0, 1, 2, 3, 5, 6, 7]
>>> l.pop(-1) # item at end - equivalent to pop()
7
>>> l
[0, 1, 2, 3, 5, 6]
>>> l.pop(-2) # one left of the end
5
>>> l
[0, 1, 2, 3, 6]
>>> l.pop() # always the end item
6
>>> l
[0, 1, 2, 3]
Keep in mind that pop removes the item, and the list changes length after the pop. Use negative numbers to index from the end of a list that may be changing in size, or just use pop() with no arguments for the end item.
Since a pop can produce these errors, you often see them in an exception block:
>>> l=[]
>>> try:
... i=l.pop(5)
... except IndexError:
... print "sorry -- can't pop that"
...
sorry -- can't pop that
After you pop the 4, the list only has 7 values. If you print indexList after your pop(f), it will look like:
[0, 1, 2, 3, 5, 6, 7]
Along with all the other answers, the important part about the pop() function is that it removes the value from the array, thus changing the indexes. After popping index 4, your list is left with 7 items. It is important to know that Python indexes starting at 0 so your 7 item list only contains indexes 0 through 6. That's why popping index 7 is out of bounds, it no longer exists.
Typically a "popping" function is used when implementing a stack or a queue where the goal is to get a value from a list of values waiting to be processed. To avoid processing the same data twice by accident, you make sure to remove it at the same time as retrieval.
Sometimes stacks and queues can be implemented with a peek operation that will return just the value without removing it but since Python implements stacks and queues just using regular arrays without any special wrapper, your peek function would be the standard array[index] call.
----EDIT----
It occurs to me that it could be the case that instead of removing the item at index 7, you wish to remove the value 7. If that's the case, you should call indexList.remove(7). This will remove the first instance of 7 in your list, no matter what its index (and throws an error if there is no value 7). I'm pretty sure you understand that pop() takes an index, though.
Just in case, take a look at the Python datastructures API for more information on what functions are available, what they do, and what arguments they take.