Here's a pseudocode I've written describing my problem:-
func(s):
#returns a value of s
x = a list of strings
print func(x)
print x #these two should give the SAME output
When I print the value of x in the end, I want it to be the one returned by func(x). Can I do something like this only by editing the function (and without setting x = func(x))
func(s):
s[:] = whatever after mutating
return s
x = a list of strings
print func(x)
print x
You don't actually need to return anything:
def func(s):
s[:] = [1,2,3]
x = [1,2]
print func(x)
print x # -> [1,2,3]
It all depends on what you are actually doing, appending or any direct mutation of the list will be reflected outside the function as you are actually changing the original object/list passed in. If you were doing something that created a new object and you wanted the changes reflected in the list passed in setting s[:] =.. will change the original list.
That's already how it behaves, the function can mutate the list
>>> l = ['a', 'b', 'c'] # your list of strings
>>> def add_something(x): x.append('d')
...
>>> add_something(l)
>>> l
['a', 'b', 'c', 'd']
Note however that you cannot mutate the original list in this manner
def modify(x):
x = ['something']
(The above will assign x but not the original list l)
If you want to place a new list in your list, you'll need something like:
def modify(x):
x[:] = ['something']
While coding on a python project I noticed a strange behavior when I tried to change the value of a list in another list.
Not working code:
lst = []
to_add = [None,None,None]
for i in range(3):
lst.append(to_add)
for i in range(3):
lst[i][0] = anotherslistoflists[i][0]
To my surprise this example gave unexpected results. To be specific, every lst[i][0] got assigned with the same value which was the first element from the last index of the "anotherlistoflists" list.
Result example (when printing lst)
("word1",None,None)
("word1",None,None)
("word1",None,None)
Working code:
lst = []
for i in range(5):
lst.append([None,None,None])
# same code as above
Result example2 (expected result)
("word1",None,None)
("word2",None,None)
("word3",None,None)
Of course, as you can see the problem is solved but I was wondering why the first code does not work. Something is probably wrong with the "to_add" list but I don't understand what is the problem here.
You are appending the same list, to_add, three times. Then, once you modify it, all three items which point to it will reflect the same change. If you want to create a new copy with the same values, you could use the built-in list function:
for i in range(3):
lst.append(list(to_add))
You are adding the same list, to_add to lst:
>>> a = [None]
>>> b = [a]
>>> c = [a]
>>> print a, b, c
[None] [[None]] [[None]]
>>> a[0] = 1
>>> print a, b, c
[1] [[1]] [[1]]
In the first case you are not adding a copy of add_to_list you are actually adding that exact list over and over, so when you change it later you're changing the real add_to_list and everywhere that refers to it. In the second case you're adding a new list containing None each time, and modifying different lists each time through
I am trying to write a function that squares each value in a list, returning a new list with individual values squared. I pass a list to it and it changes the original list. I'd like it to not make any changes to the original list, so that I can use it in other functions.
def squareset(c):
d=c
count = len(c)
print(c)
for i in range(0,(count),1):
d[i]=d[i]**2
return d
test = [1,2,3]
print(squareset(test))
print(test)
I don't have this problem with functions operating on simple variables of type int or float.
I added the d=c line trying to prevent the change to the list test, but it makes no difference. print(test) is producing the result [1,4,9] instead of [1,2,3]. Why is this happening and how can I fix this?
Doing d=c simply makes the parameter d point to the same object that c is pointing to. Hence, every change made to d is made to the same object that c points to.
If you want to avoid changing c you'll have to either send a copy of the object, or make a copy of the object inside the function and use this copy.
For example, do:
d = [i for i in c]
or:
d = c[:]
instead of:
d = c
Assigning the list to another variable doesn't copy the list. To copy, just
def squareset(c):
d=c[:]
...
While the other answers provided are correct I would suggest using list comprehension to square your list.
In [4]:
test = [1,2,3]
results = [elm**2 for elm in test]
print test
print results
[1, 2, 3]
[1, 4, 9]
If you wanted a function:
def squareList(lst):
return [elm**2 for elm in lst]
Try this:
def square(var):
return [x*x for x in var]
x = [1,2,3]
z = square(x)
a = ['a']
b = ['b']
c = a
ab = [a,b]
print(c)
print(ab)
a[0] = 'c'
print(c)
print(ab)
Returns:
['a']
[['a'], ['b']]
['c']
[['c'], ['b']]
I wanted the c list to remain what it was i.e. ['a']. But it changed after I changed the element in the a list. Why does this happen and how, if at all, can I avoid it.
You need to copy the list a and assign it to c. Right now you are just assigning the reference to a to c, which is why when you modify a you also modify c. There are multiple ways to copy a, I think the easiest to read uses the list constructor:
c = list(a)
Alek's or mtitan8's solutions are probably the most convenient. To be very explicit, you can import copy and then use c = copy.copy(a)
Why doesn't list have a safe "get" method like dictionary?
>>> d = {'a':'b'}
>>> d['a']
'b'
>>> d['c']
KeyError: 'c'
>>> d.get('c', 'fail')
'fail'
>>> l = [1]
>>> l[10]
IndexError: list index out of range
Ultimately it probably doesn't have a safe .get method because a dict is an associative collection (values are associated with names) where it is inefficient to check if a key is present (and return its value) without throwing an exception, while it is super trivial to avoid exceptions accessing list elements (as the len method is very fast). The .get method allows you to query the value associated with a name, not directly access the 37th item in the dictionary (which would be more like what you're asking of your list).
Of course, you can easily implement this yourself:
def safe_list_get (l, idx, default):
try:
return l[idx]
except IndexError:
return default
You could even monkeypatch it onto the __builtins__.list constructor in __main__, but that would be a less pervasive change since most code doesn't use it. If you just wanted to use this with lists created by your own code you could simply subclass list and add the get method.
This works if you want the first element, like my_list.get(0)
>>> my_list = [1,2,3]
>>> next(iter(my_list), 'fail')
1
>>> my_list = []
>>> next(iter(my_list), 'fail')
'fail'
I know it's not exactly what you asked for but it might help others.
Probably because it just didn't make much sense for list semantics. However, you can easily create your own by subclassing.
class safelist(list):
def get(self, index, default=None):
try:
return self.__getitem__(index)
except IndexError:
return default
def _test():
l = safelist(range(10))
print l.get(20, "oops")
if __name__ == "__main__":
_test()
Instead of using .get, using like this should be ok for lists. Just a usage difference.
>>> l = [1]
>>> l[10] if 10 < len(l) else 'fail'
'fail'
Credits to jose.angel.jimenez and Gus Bus.
For the "oneliner" fans…
If you want the first element of a list or if you want a default value if the list is empty try:
liste = ['a', 'b', 'c']
value = (liste[0:1] or ('default',))[0]
print(value)
returns a
and
liste = []
value = (liste[0:1] or ('default',))[0]
print(value)
returns default
Examples for other elements…
liste = ['a', 'b', 'c']
print(liste[0:1]) # returns ['a']
print(liste[1:2]) # returns ['b']
print(liste[2:3]) # returns ['c']
print(liste[3:4]) # returns []
With default fallback…
liste = ['a', 'b', 'c']
print((liste[0:1] or ('default',))[0]) # returns a
print((liste[1:2] or ('default',))[0]) # returns b
print((liste[2:3] or ('default',))[0]) # returns c
print((liste[3:4] or ('default',))[0]) # returns default
Possibly shorter:
liste = ['a', 'b', 'c']
value, = liste[:1] or ('default',)
print(value) # returns a
It looks like you need the comma before the equal sign, the equal sign and the latter parenthesis.
More general:
liste = ['a', 'b', 'c']
f = lambda l, x, d: l[x:x+1] and l[x] or d
print(f(liste, 0, 'default')) # returns a
print(f(liste, 1, 'default')) # returns b
print(f(liste, 2, 'default')) # returns c
print(f(liste, 3, 'default')) # returns default
Tested with Python 3.6.0 (v3.6.0:41df79263a11, Dec 22 2016, 17:23:13)
Try this:
>>> i = 3
>>> a = [1, 2, 3, 4]
>>> next(iter(a[i:]), 'fail')
4
>>> next(iter(a[i + 1:]), 'fail')
'fail'
A reasonable thing you can do is to convert the list into a dict and then access it with the get method:
>>> my_list = ['a', 'b', 'c', 'd', 'e']
>>> my_dict = dict(enumerate(my_list))
>>> print my_dict
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e'}
>>> my_dict.get(2)
'c'
>>> my_dict.get(10, 'N/A')
So I did some more research into this and it turns out there isn't anything specific for this. I got excited when I found list.index(value), it returns the index of a specified item, but there isn't anything for getting the value at a specific index. So if you don't want to use the safe_list_get solution which I think is pretty good. Here are some 1 liner if statements that can get the job done for you depending on the scenario:
>>> x = [1, 2, 3]
>>> el = x[4] if len(x) > 4 else 'No'
>>> el
'No'
You can also use None instead of 'No', which makes more sense.:
>>> x = [1, 2, 3]
>>> i = 2
>>> el_i = x[i] if len(x) == i+1 else None
Also if you want to just get the first or last item in the list, this works
end_el = x[-1] if x else None
You can also make these into functions but I still liked the IndexError exception solution. I experimented with a dummied down version of the safe_list_get solution and made it a bit simpler (no default):
def list_get(l, i):
try:
return l[i]
except IndexError:
return None
Haven't benchmarked to see what is fastest.
Dictionaries are for look ups. It makes sense to ask if an entry exists or not. Lists are usually iterated. It isn't common to ask if L[10] exists but rather if the length of L is 11.
If you
want a one liner,
prefer not having try / except in your happy code path where you needn't, and
want the default value to be optional,
you can use this:
list_get = lambda l, x, d=None: d if not l[x:x+1] else l[x]
Usage looks like:
>>> list_get(['foo'], 4) == None
True
>>> list_get(['hootenanny'], 4, 'ho down!')
'ho down!'
>>> list_get([''], 0)
''
For small index values you can implement
my_list.get(index, default)
as
(my_list + [default] * (index + 1))[index]
If you know in advance what index is then this can be simplified, for example if you knew it was 1 then you could do
(my_list + [default, default])[index]
Because lists are forward packed the only fail case we need to worry about is running off the end of the list. This approach pads the end of the list with enough defaults to guarantee that index is covered.
This isn't an extremely general-purpose solution, but I had a case where I expected a list of length 3 to 5 (with a guarding if), and I was breaking out the values to named variables. A simple and concise way I found for this involved:
foo = (argv + [None, None])[3]
bar = (argv + [None, None])[4]
Now foo and bar are either the 4th and 5th values in the list, or None if there weren't that many values.
Your usecase is basically only relevant for when doing arrays and matrixes of a fixed length, so that you know how long they are before hand. In that case you typically also create them before hand filling them up with None or 0, so that in fact any index you will use already exists.
You could say this: I need .get() on dictionaries quite often. After ten years as a full time programmer I don't think I have ever needed it on a list. :)