Unpack into the list append method in Python - python

I run into a problem when unpacking a tuple. I want the first value to be appended to a list and a second assigned to a variable. For example:
list = []
tuple = (1, 2)
list.append, variable = tuple
But this raises an exception since I am assigning to a bultin and not actually calling in. Is that possible in Python? Or even a simpler operation such as:
a, b = 5, 4
tuple = (1, 2)
a+, b = tuple
to yield a = 6, b = 2.

There's no brief syntax to allow this. However, here's a class that creates a wrapper around a list, so that assigning to an append attribute really calls the underlying list's append method. This could be useful if you have a lot of values to append to the list.
class Appender:
def __init__(self, lst):
self.lst = lst
# The rare write-only property
append = property(None, lambda self, v: self.lst.append(v))
values = []
value_appender = Appender(values)
value_appender.append, b = (1,2)
assert values == [1]
Perhaps simpler, a subclass of list with a similar property:
class Appendable(list):
take = property(None, lambda self, v: self.append(v))
values = Appendable()
values.take, b = (1, 2)
assert values == [1]

append is a method on the builtin list type. Python allows tuple unpacking into variables in one line as a convenience, but it won't decide to call the append method with part of your tuple as an argument. Just write your code on multiple lines, that will help make it easier to read too.
my_list = []
my_tuple = (1, 2)
a, b = my_tuple
my_list.append(a)

Technically yes you could do it in a single line, but I wouldn't.
l = []
a = (1,2)
l[:0], b = [[x] if c == 0 else x for c,x in enumerate(a)]
>>> l
[1]
>>> b
2

You can use the map function on the append method for the list.
>>> a = (6,7)
>>> b = [1,2,3,4,5]
>>> list(map(b.append, a))
[None, None]
>>> b
[1, 2, 3, 4, 5, 6, 7]
I am not really sure what the list() does in this statement but it seems to work.

Related

What is the difference between del a_list[:] and a_list = [] in a function?

This is just a question asking for the difference in the code.
I have several lists ie. a=[], b=[], c=[], d=[]
Say if I have a code that appends to each list, and I want to reset all these lists to its original empty state, I created a function:
def reset_list():
del a[:]
del b[:]
del c[:]
del d[:]
So whenever I call reset_list() in a code, it removes all the appended items and set all lists to []. However, the one below doesn't work:
def reset_list():
a = []
b = []
c = []
d = []
This might be a stupid question but I was wondering why the second one wouldn't work.
When you do del a[:] then it looks for the variable a (including outer contexts) and then performs del found_a[:] on it.
But when you use a = [] it creates a name a in the current context and assigns an empty list to it. When the function exits the variable a from the function is not "accessible" anymore (destroyed).
So in short the first works because you change the a from an outer context, the second does not work because you don't modify the a from the outer context, you just create a new a name and temporarily (for the duration of the function) assigns an empty list to it.
There's a difference between del a[:] and a = []
Note that these actually do something different which becomes apparent if you have additional references (aliases) to the original list. (as noted by #juanpa.arrivillaga in the comments)
del list[:] deletes all elements in the list but doesn't create a new list, so the aliases are updated as well:
>>> list_1 = [1,2,3]
>>> alias_1 = list_1
>>> del alist_1[:]
>>> list_1
[]
>>> alias_1
[]
However a = [] creates a new list and assigns that to a:
>>> list_2 = [1,2,3]
>>> alias_2 = list_2
>>> list_2 = []
>>> list_2
[]
>>> alias_2
[1, 2, 3]
If you want a more extensive discussion about names and references in Python I can highly recommend Ned Batchelders blog post on "Facts and myths about Python names and values".
A better solution?
In most cases where you have multiple variables that belong together I would use a class for them. Then instead of reset you could simply create a new instance and work on that:
class FourLists:
def __init__(self):
self.a = []
self.b = []
self.c = []
self.d = []
Then you can create a new instance and work with the attributes of that instance:
>>> state = FourLists()
>>> state.a
[]
>>> state.b.append(10)
>>> state.b.extend([1,2,3])
>>> state.b
[10, 1, 2, 3]
Then if you want to reset the state you could simply create a new instance:
>>> new_state = FourLists()
>>> new_state.b
[]
You need to declare a,b,c,d as global if you want python to use the globally defined 'versions' of your variables. Otherwise, as pointed out in other answers, it will simply declare new local-scope 'versions'.
a = [1,2,3]
b = [1,2,3]
c = [1,2,3]
d = [1,2,3]
def reset_list():
global a,b,c,d
a = []
b = []
c = []
d = []
print(a,b,c,d)
reset_list()
print(a,b,c,d)
Outputs:
[1, 2, 3] [1, 2, 3] [1, 2, 3] [1, 2, 3]
[] [] [] []
As pointed out by #juanpa.arrivillaga, there is a difference between del a[:] and a = []. See this answer.
The 1st method works because:
reset_list() simply deletes the contents of the four lists. It works on the lists that you define outside the function, provided they are named the same. If you had a different name, you'd get an error:
e = [1,2,3,4]
def reset_list():
del a[:] #different name for list
NameError: name 'e' is not defined
The function will only have an effect if you initialize the lists before the function call. This is because you are not returning the lists back after the function call ends:
a = [1,2,3,4] #initialize before function definition
def reset_list():
del a[:]
reset_list() #function call to modify a
print(a)
#[]
By itself the function does not return anything:
print(reset_list())
#None
The 2nd method doesn't work because:
the reset_list() function creates 4 empty lists that are not pointing to the lists that may have been defined outside the function. Whatever happens inside the function stays inside(also called scope) and ends there unless you return the lists back at the end of the function call. The lists will be modified and returned only when the function is called. Make sure that you specify the arguments in reset_list(a,..) in the function definition:
#function definition
def reset_list(a):
a = []
return a
#initialize list after function call
a = [1,2,3,4]
print("Before function call:{}".format(a))
new_a = reset_list(a)
print("After function call:{}".format(new_a))
#Output:
Before function call:[1, 2, 3, 4]
After function call:[]
As you've seen, you should always return from a function to make sure that your function "does some work" on the lists and returns the result in the end.
The second function (with a = [ ] and so on) initialises 4 new lists with a local scope (within the function). It is not the same as deleting the contents of the list.

Creating flat list from single float or list of floats

I wish to iterate over a zip of objects and floats together using a parent class function. Sometimes the subclasses have three objects and three floats in a list, this works fine:
L = [A,B,C]
F = [1,2,3]
for f, o in zip(L,F):
# do stuff
Sometimes the subclass has one object and one float
L = A
F = 1
for f, o in zip(L,F):
# TypeError
This throws an exception because F is not iterable.
If I try:
F = list(F)
This works for 2 or more floats but throws an exception for a single float (it's still not iterable :)).
If I try:
F = [F]
This solves the 1 float case but now returns a nested list when there are two or more floats!
a = [1,2]
[a] = [[1,2]]
Is there a simple builtin way to receive either a single float or list of floats and return a single flat list? Or do I need something like itertools.chain?
Just check if you already have a list, and if not create one with a single element:
f = f if isinstance(f,list) else [f]
For example:
>>> f = 1
>>> f = f if isinstance(f,list) else [f]
>>> f
[1]
>>> f = [1,2]
>>> f = f if isinstance(f,list) else [f]
>>> f
[1, 2]
Note, I'm assuming your using lists but you could use collections.Iterable for a more generic solution.
Further note, I don't know where F/f came from, but ideally it would have been initially created this way rather than fixing it now.
You can try a = a if isinstance(a, collections.Iterable) else [a]. This makes sure a is either iterable or converts it to list. Also you need not convert a, you could assign the result to another variable.
You can design your objects so that they have a builtin __iter__ method along with __len__:
class CertainObject:
def __init__(self):
self.variables = [23, 4, 2]
def __len__(self):
return len(self.variables)
def __iter__(self):
for i in self.variables:
yield i
Case 1(Multiple objects):
L = [CertainObject(), CertainObject(),CertainObject()]
F = [1,2,3]
for f, o in zip(L,F):
pass
Case 1 (singe object):
A = CertainObject()
F = 1
for a, b in zip(A, [F]*len(A)):
print(a, b)
With __iter__, iterating over the instance of the object will not raise an error.
You can use your case that returns a nested list, but then cast the list as a numpy array and use the flatten() function, then re-cast as a list if you want it that way.
a = list(np.array(a).flatten())
This way, a = 1 will turn into [1], a = [1, 2] will turn into [1, 2], and a = [[1, 2]] will turn into [1, 2], so all outputs are lists.
Use extend
L = []
F = []
L.extend([A])
F.extend([B])
for f,o in zip(L,F):
# do stuff
This should not give you problems both with one item lists and with more than one item lists (it won't be nested).
example 1 item:
L = []
F = []
A = 1
B = 1
L.extend([A])
F.extend([B])
for f,o in zip(L,F):
print(f,o)
otput
1 1
Example more items
L = []
F = []
A = [1,2,3]
B = [1,2,3]
L.extend([A])
F.extend([B])
for f,o in zip(L,F):
print(f,o)
output
1 1
2 2
3 3

Copy values from one list to another without altering the reference in python

In python objects such as lists are passed by reference. Assignment with the = operator assigns by reference. So this function:
def modify_list(A):
A = [1,2,3,4]
Takes a reference to list and labels it A, but then sets the local variable A to a new reference; the list passed by the calling scope is not modified.
test = []
modify_list(test)
print(test)
prints []
However I could do this:
def modify_list(A):
A += [1,2,3,4]
test = []
modify_list(test)
print(test)
Prints [1,2,3,4]
How can I assign a list passed by reference to contain the values of another list? What I am looking for is something functionally equivelant to the following, but simpler:
def modify_list(A):
list_values = [1,2,3,4]
for i in range(min(len(A), len(list_values))):
A[i] = list_values[i]
for i in range(len(list_values), len(A)):
del A[i]
for i in range(len(A), len(list_values)):
A += [list_values[i]]
And yes, I know that this is not a good way to do <whatever I want to do>, I am just asking out of curiosity not necessity.
You can do a slice assignment:
>>> def mod_list(A, new_A):
... A[:]=new_A
...
>>> liA=[1,2,3]
>>> new=[3,4,5,6,7]
>>> mod_list(liA, new)
>>> liA
[3, 4, 5, 6, 7]
The simplest solution is to use:
def modify_list(A):
A[::] = [1, 2, 3, 4]
To overwrite the contents of a list with another list (or an arbitrary iterable), you can use the slice-assignment syntax:
A = B = [1,2,3]
A[:] = [4,5,6,7]
print(A) # [4,5,6,7]
print(A is B) # True
Slice assignment is implemented on most of the mutable built-in types. The above assignment is essentially the same the following:
A.__setitem__(slice(None, None, None), [4,5,6,7])
So the same magic function (__setitem__) is called when a regular item assignment happens, only that the item index is now a slice object, which represents the item range to be overwritten. Based on this example you can even support slice assignment in your own types.

Python - external variable being changed by function

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)

Best method to clear list and dictionary

Code:
num_of_iterations_for_outer_loop = 2
num_of_iterations_for_inner_loop = 3
data = []
for j in range(num_of_iterations_for_outer_loop):
lst2 = []
for k in range(num_of_iterations_for_inner_loop):
lst1 = {}
lst1['1'] = "first_value" # these are not default, in my original code they are coming from some other values after calculation
lst1['2'] = "second_value"
lst1['3'] = "third_value"
lst2.append(lst1)
value = {'values':lst2}
data.append(value)
In the outer loop I have to clear lst2 list again and again for reusing it.
In the inner loop I have to clear lst1 dictionary again and again for reusing it.
I know 2 methods of clearing a list:
del lst2[:]
lst2 = []
and 1 method for clearing a dictionary:
lst1 = {}
But I don't know differences between these methods and which one I should use.
Is there any other method to clear the list and dictionary? And is that better method, and why?
Is there any better method to write the whole code?
Here is a brief idea of what each method does:
lst2 = [] does not actually clear the contents of the list. It just creates a new empty list and assign it to the name lst2. Then it is the task of GC to delete the actual contents based on the remaining references.
>>> a = [1,2,3]
>>> b = a
>>> a = []
>>> a
[]
>>> b
[1, 2, 3]
del lst2[:] clears the contents of the list in-place.
>>> a = [1,2,3]
>>> b = a
>>> del a[:]
>>> a
[]
>>> b
[]
Note that the other list b also gets cleared because the contents are deleted in-place.
lst1 = {} is same as point 1. It creates an empty dictionary and assigns the reference to the name lst1.
Another method to clear the list in-place is:
lst2[:] = []
The differences between your two methods of "clearing" the list is that the first operates in-place, deleting the contents of the original list object, while the second simply creates a new list object and assigns it to the same name. You must use the second version here, otherwise all of the lists in your dictionary will be copies of the same emptied list at the end:
>>> l = [1, 2, 3]
>>> d = {'a': l}
>>> del l[:]
>>> d
{'a': []}
Similarly, you can del all the key-value pairs from a dictionary, but you would have the same problem. As you are putting the original container objects into some other container, you should create a new container by assignment (e.g. lst1 = {}) in each loop.
Is there any better method to write the whole code ?
I don't know what else you're doing with the data, but the dictionary value may be unnecessary, and a three-tuple of the innermost data could be sufficient:
data = [[(1, 2, 3), (4, 5, 6)], [(7, 8, 9), ...], ...]
Assignments are pretty much good and efficient methods to clear list or dict.
my_dict = {}
and my_list = []
Nothing fancy needed.

Categories