Wierd Behavior Appending to list inside function [duplicate] - python

This question already has answers here:
How do I pass a variable by reference?
(39 answers)
Closed 8 years ago.
def test(list2):
list2.append(1)
print len(list2)
print len(LIST1)
LIST1 = [1]
while len(LIST1) < 9:
test(LIST1)
Please explain why 'LIST1' is increasing in size if I'm appending to 'list2', isn't variables inside functions local? And above all, how can I circumvent this?
The same happens if I make a new variable:
def test(arg_list):
list2 = arg_list
list2.append(1)
print len(list2)
print len(LIST1)
LIST1 = [1]
while len(LIST1) < 9:
test(LIST1)

No, parameters passed to a function are by reference, and in the second example the local variable is yet another reference to the same list. Parameter passing and variable assignment do not create copies of the list, only references to the same object. In other words: anything you do to an object being referenced inside the function (say, a list) will be reflected on the object itself once the function exits - the function parameter and the object "outside" the function are one and the same.
How can you circumvent this? well, if it fits your usage scenario you can simply copy the list before passing it as a parameter, like this:
test(LIST1[:])
The above will create a new, different list (it's a shallow copy, though ... for performing a deep copy use copy.deepcopy), which you can safely modify inside the function, as the list "outside" the function will remain unchanged.

Related

How do I make a program in Python that tells whether or not a list is a "palindrome"? [duplicate]

This question already has answers here:
How can I get a reversed copy of a list (avoid a separate statement when chaining a method after .reverse)?
(11 answers)
Python a = a.reverse makes the list empty?
(7 answers)
Closed 1 year ago.
Here is the question I am trying to answer:
Write code that accepts a list of strings as its parameter and indicates whether that list is a palindrome. A palindrome list is one that reads the same forward as backward. For example, the list ["alpha", "beta", "gamma", "delta", "gamma", "beta", "alpha"] is a palindrome.
def palindrome_checker(list):
if list == list.reverse():
print('Palindrome')
else:
print('Not Palindrome')
user_list = []
user_input = (input('Enter list of words'))
user_list = [user_input.split()]
palindrome_checker(user_list)
My code responds "Not Palindrome" no matter what. Can anyone tell me what I am missing?w
list.reverse() does not return the reversed version of the list, it actually doesn't return anything at all. The reverse function actually changes the original list object.
So basically, you're saying if list == None in that statement.
Does that make sense?
You can generally assume anytime you call a method that belongs to an object, for example in this case, the reverse() method in the List object, that the method is going to change the original object, not return a new value.
What you want is:
reversedList = list(reversed(original_list))
if original_list = reversed_list:
On another note, I suggest you rename your parameter from list to something else for the sake of cleanliness. You want to avoid namespace collisions since the word list already refers to the type list and the method list that constructs a list.
For fun a variation on #bdbd answer:
def palindrome_checker(l):
return ('' if l == list(reversed(l)) else 'Not ') + 'Palindrome'
Aside from the answers already here, you can also do:
my_list == list(reversed(my_list))
or
list == list[::-1]
EDIT:
First one will fail because of conflicting names on list, since it's a reserved keyword built-in function. I suggest change the name of your variable as well to something different if you choose the first approach
reverse is an inplace function i.e it returns None. So a list is never equal to None. Also, .split() itself provides a list. [user_input.split()] will create a nested list.
So a solution.
Remove the [] from .split()
Create a copy of the list before you reverse it.
def palindrome_checker(lists):
lists2=lists[:]
lists.reverse()
if lists2 == lists:
print('Palindrome')
else:
print('Not Palindrome')
user_list = []
user_input = (input('Enter list of words'))
user_list = user_input.split()
palindrome_checker(user_list)

How do change the list value? [duplicate]

This question already has answers here:
How do I pass a variable by reference?
(39 answers)
Closed 1 year ago.
def double_reverse(words_list):
reverse = []
reverse1= []
reverse = words_list[::-1]
for i in reverse:
reverse1.append(i[::-1])
words_list = reverse1
Hi there,
I have this question for a practice assessment:
Question
For this question, I cannot return or print anything. Instead, I need to update the words_list list value so that I can get the desired result.
However, for some reason I can only get the original list. Why is the list not being updated?
Cheers
words_list = reverse1
just rebinds the local variable words_list. It does not mutate the object that this variable referenced before (the one that got passed in as a function argument). A simple fix would be slice assignment:
words_list[:] = reverse1
which constitutes a mutation on said object.
A general pythonic simplification of your function could be:
def double_reverse(words_list):
words_list[:] = [w[::-1] for w in reversed(words_list)]

Changing list while iterating [duplicate]

This question already has answers here:
Modifying a list while iterating over it - why not? [duplicate]
(4 answers)
Closed 6 years ago.
I've found a python puzzle and can't find out why it works.
x = ['a','b','c']
for m in x:
x.remove(m)
and after this loop x = ['b'].
But why?
As far as I understand for keyword implicitly creates iterator for this list. Does .remove() calls __next__() method so b is skipped? I can't find any mentions of it but this is my best guess.
Here you are iterating over the original list. On the first iteration, you removed the 0th index element i.e. a. Now, your list is as: ['b','c']. On the second iteration your for loop will access the value at index 1 but your index 1 has value c. So the c is removed. Hence resultant list will be ['b'].
In order to make it behave expectedly, iterate over the copy of the list, and remove the item from original list. For example:
x = ['a','b','c']
for m in list(x): # <-- Here 'list(x)' will create the copy of list 'x'
# for will iterate over the copy
x.remove(m)
# updated value of 'x' will be: []
Note: If it is not for demo purpose and you are using this code for emptying the list, efficient way of emptying the list will be:
del x[:]

Are Python arguments passed by reference? [duplicate]

This question already has answers here:
How do I pass a variable by reference?
(39 answers)
Closed 7 years ago.
In detail, my question is this:
Given the following code,
x = 10
def func(x):
x = x+1
def main():
print(x)
func(x)
print(x)
if __name__ == '__main__':
main()
On running this I get:
10
10
Does this mean that Python does not pass values by reference?
And I did check through the other question of the sort, and most(if not all) included analogies of lists or other such examples.
Is it possible to explain this in simple terms, like just a simple integer?
Ps. I am a beginner to coding.
Thanks
If you are coming from a background such as C or C++, which I did, this can be maddening until you figure it out.
Python has names, not variables, and names are bound to objects. Effectively, you can think of all 'variables' or names, as being pointers to python objects.
In python, integers, floats, and strings are immutable. So when you do the following:
x = 10
x = x + 1
You are first binding the name x to the integer 10, then when you evaluate x + 1 you get a new object 11 and then you bind x to that object. Your x inside the function body is local to the function, and when you bind it to 11, the global x remains bound to 10.
If you were to pass a list to the function, and append something to the list, that list would be modified. A list in python is a mutable object. All names bound to the list would refer to the modified list.
As a result, when you pass mutable objects it may seem as if you are passing by reference, and when you pass immutable objects it may seem like you are passing by value.

How to get a copy from a list? [duplicate]

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 9 years ago.
I am trying to get an element from list and make some change on this element (which is also a list). Weirdly, the change applied on the previous list. Here is my code:
>>>sentences[0]
['<s>/<s>',
'I/PRP',
'need/VBP',
'to/TO',
'have/VB',
'dinner/NN',
'served/VBN',
'</s>/</s>']
>>>sentence = sentences[0]
>>>sentence.insert(0,startc); sentence.append(endc)
>>>sentences[0]
['<s>/<s>',
'<s>/<s>',
'I/PRP',
'need/VBP',
'to/TO',
'have/VB',
'dinner/NN',
'served/VBN',
'</s>/</s>'
'</s>/</s>']
It is like I just got a pointer to that element, not a copy
You do get a "pointer", in fact. Lists (and any mutable value type!) are passed around as reference in Python.
You can make a copy of a list by passing it to the list() object constructor, or by making a full slice using [:].
a = [1,2,3]
b = a
c = list(a)
d = a[:]
a[1] = 4 # changes the list referenced by both 'a' and 'b', but not 'c' or 'd'
You're exactly right! In Python, when you pass a list as an argument to a function, or you assign a list to another variable, you're actually passing a pointer to it.
This is for efficiency reasons; if you made a separate copy of a 1000-item list every time you did one of the aforementioned things, the program would consume way too much memory and time.
To overcome this in Python, you can duplicate a one-dimensional list using = originalList[:] or = list(originalList):
sentence = sentences[0][:] # or sentence = list(sentences[0])
sentence.insert(0,startc)
sentence.append(endc)
print(sentence) # modified
print(sentences[0]) # not modified
Consider using list comprehension if you need to duplicate a 2D list.

Categories