What does the list() function do in Python? - python

I know that the list() constructor creates a new list but what exactly are its characteristics?
What happens when you call list((1,2,3,4,[5,6,7,8],9))?
What happens when you call list([[[2,3,4]]])?
What happens when you call list([[1,2,3],[4,5,6]])?
From what I can tell, calling the constructor list removes the most outer braces (tuple or list) and replaces them with []. Is this true? What other nuances does list() have?

list() converts the iterable passed to it to a list. If the itertable is already a list then a shallow copy is returned, i.e only the outermost container is new rest of the objects are still the same.
>>> t = (1,2,3,4,[5,6,7,8],9)
>>> lst = list(t)
>>> lst[4] is t[4] #outermost container is now a list() but inner items are still same.
True
>>> lst1 = [[[2,3,4]]]
>>> id(lst1)
140270501696936
>>> lst2 = list(lst1)
>>> id(lst2)
140270478302096
>>> lst1[0] is lst2[0]
True

Python has a well-established documentation set for every release version, readable at https://docs.python.org/. The documentation for list() states that list() is merely a way of constructing a list object, of which these are the listed ways:
Using a pair of square brackets to denote the empty list: []
Using square brackets, separating items with commas: [a], [a, b, c]
Using a list comprehension: [x for x in iterable]
Using the type constructor: list() or list(iterable)
The list() function accepts any iterable as its argument, and the return value is a list object.
Further reading: https://docs.python.org/3.4/library/stdtypes.html#typesseq-list

Yes it is true.
Its very simple. list() takes an iterable object as input and adds its elements to a newly created list. Elements can be anything. It can also be an another list or an iterable object, and it will be added to the new list as it is.
i.e no nested processing will happen.

You said: "From what I can tell, calling the constructor list removes the most outer braces (tuple or list) and replaces them with []. Is this true?"
IMHO, this is not a good way to think about what list() does. True, square brackets [] are used to write a list literal, and are used when you tell a list to represent itself as a string, but ultimately, that's just notation. It's better to think of a Python list as a particular kind of container object with certain properties, eg it's ordered, indexable, iterable, mutable, etc.
Thinking of the list() constructor in terms of it performing a transformation on the kind of brackets of a tuple that you pass it is a bit like saying adding 3 to 6 turns the 6 upside down to make 9. It's true that a '9' glyph looks like a '6' glyph turned upside down, but that's got nothing to do with what happens on the arithmetic level, and it's not even true of all fonts.

aTuple = (123, 'xyz', 'zara', 'abc');
aList = list(aTuple)
print "List elements : ", aList
When we run above program, it produces following result:
List elements : [123, 'xyz', 'zara', 'abc']
It is another way to create a list in python. How convenient!

Your question is vague, but this is the output as follows, it doesn't "replace" the outer braces, it creates a data structure of a list, that can contain any value in a "listed" order (one after the other, after the other, and so on...) in a recursive way, you can add/remove elements to a specified index using append and pop. By the other hand, tuples are static and are not dynamically linked, they are more like an array of any type of element.
WHEN:
list((1,2,3,4,[5,6,7,8],9))
RETURNS:
[1, 2, 3, 4, [5, 6, 7, 8], 9]
WHEN:
list([[[2,3,4]]])
RETURNS:
[[[2, 3, 4]]]
WHEN:
list([[1,2,3],[4,5,6]])
RETURNS:
[[1, 2, 3], [4, 5, 6]]

Related

The operations for sum([[3], [5]], [])

This is a very simple expression, but I have no idea how it operates.
print(sum([[3], [5]], []))
# returns [3,5]
why on earth does sum([[3], [5]], []) return [3,5]? My knowledge on sum() is that it takes in an iterable and sums the elements in the iterable. So usually the elements are integers.
For example, I'm familiar with something like:
sum([1,2,3])
# returns 6
But sum([[3], [5]], []) has two inputs, one a list of lists, and another an empty list. I thought this would return an error, but surprisingly it returned the above result. I haven't seen something like this before, and I would appreciate it if anyone could tell me the operations going on for this example.
sum() takes two parameters :
the iterable (here [[3],[5]])
the start, which has a default value of 0 (an int)
When you use
sum([[3],[5]])
start has the default value 0, so the function tries to add [3] and [5] to 0, an int, so you have TypeError.
On the other hand, when you use
sum([[3],[5]],[])
with [] as start value, [] + [3] + [5], it first instantiates an empty list before adding list-type elements to it.
This sum is correct with output [3,5]
This is equivalent to:
s = []
for lst in [[3], [5]]:
s += lst
You need to know that the list can be connected through the operator +,even if it contains an empty list, it will get a copy of another list.
About why sum ([[3], [5]]) raise error, see the signature of sum function:
sum(iterable, start)
If you don't specify start, the default value seems to be 0, which of course cannot be added to the list.

Python: Why assigning list values inline returns a list of "None" elements?

I'm still new to Python, and I've been making a small function that reverses a list of lists, both the original list and the lists inside. This is my code:
def deep_reverse(L):
L.reverse()
L = [i.reverse() for i in L]
Now this code works perfectly, but if I do a small change and rearrange the lines like this:
def deep_reverse(L):
L = [i.reverse() for i in L]
L.reverse()
suddenly it stops working! It only reverses the internal lists but not the original one. Putting some debugging print() statements inside, I can see the first code reverses the original list after the first line and it's printed, but the second code actually prints a list containing 'None' as elements after reversing the list. Can anyone please explain why this behavior and what is the difference between the two codes?
The reverse() function reverses a list in-place and returns None, that explains the weird behavior. A correct implementation would be:
def deep_reverse(L):
ans = [i[::-1] for i in L]
ans.reverse()
return ans
Also, it's a bad idea to reassign and/or mutate a parameter to a function, it can lead to unexpected results. Sometimes functions in the standard library do it for efficiency reasons (for example, sort() and reverse()), that's ok - but it can lead to confusions, like the one you just experienced. Your code doesn't have to be written in that fashion unless strictly necessary.
Your first deep_reverse function reassigned L, but it is not a global parameter and is not returned in your function. Hence this variable is lost. HOWEVER, you are mutating the list in place, hence the modifications remain which is why it still works! Your original function is equivalent to the following (note there is no final assignment):
def deep_reverse(L):
L.reverse()
[i.reverse() for i in L]
This should probably be written using a for-loop:
def deep_reverse_2(L):
L.reverse()
for i in L:
i.reverse()
L = [[1, 2, 3], [2, 3, 4]]
deep_reverse_2(L)
>>> L
[[4, 3, 2], [3, 2, 1]]
The second function does not work because you reassign L inside the function (it is now local to the function and not the same L variable you passed in to the function). They would have different memory locations if you checked using id. Given that nothing is returned, this new L list is lost, as are the modifications made to it.

reverse() usage in python?

The sort() and reverse() methods modify the list in place for economy of space when sorting or reversing a large list. To remind you that they operate by side effect, they don’t return the sorted or reversed list.
The above text can be found at http://docs.python.org/2/library/stdtypes.html#mutable-sequence-types
What does "modify the list in place for economy of space" mean?
Example:
x = ["happy", "sad"]
y = x.reverse()
would return None to y. So then why does,
x.reverse()
Successfully reverse x?
What does "modify the list in place for economy of space" mean?
What this means is that it does not create a copy of the list.
why does, x.reverse() Successfully reverse x?
I don't understand this question. It does this because that's what it's designed to do (reverse x and return None).
Note that sort() and reverse() have counterparts that don't modify the original and return a copy. These functions are called sorted() and reversed():
In [7]: x = [1, 2, 3]
In [8]: y = list(reversed(x))
In [9]: x
Out[9]: [1, 2, 3]
In [10]: y
Out[10]: [3, 2, 1]
list.reverse reverses the list in-place and returns None, it's designed to do so, similar to append, remove, extend, insert, etc.
In [771]: x = ["happy", "sad"]
In [772]: x.reverse()
In [773]: x
Out[773]: ['sad', 'happy']
In almost any programming language there are two kinds of callable definitions: functions and procedures.
Functions are methods or subroutines that do some processing and return a value. For instance, a function to sum two integers a and b will return the result of the sum a + b.
In the other hand, procedures are pretty much the same (even in the syntax in most languages) with the slight difference that don't return a value, and of course they are used by their side effects, meaning that they change the state of something or just process some data and save it or just print it out to a file.
So in this case, reverse would act as a procedure, which changes the state of the list being reversed (by reversing it), and here is how this can be done without extra space:
def reverse(l):
for i in range(len(l) / 2):
l[i], l[-i-1] = l[-i-1], l[i]
Notice that a new list is never created, instead, what the code does is to interchange the elements of the list l in place by swapping the first and the last, the second and the penultimate and so on until the element in the half of the list.
Hope this helps you understand ;)

Removing duplicates and preserving order when elements inside the list is list itself

I have a following problem while trying to do some nodal analysis:
For example:
my_list=[[1,2,3,1],[2,3,1,2],[3,2,1,3]]
I want to write a function that treats the element_list inside my_list in a following way:
-The number of occurrence of certain element inside the list of my_list is not important and, as long as the unique elements inside the list are same, they are identical.
Find the identical loop based on the above premises and only keep the
first one and ignore other identical lists of my_list while preserving
the order.
Thus, in above example the function should return just the first list which is [1,2,3,1] because all the lists inside my_list are equal based on above premises.
I wrote a function in python to do this but I think it can be shortened and I am not sure if this is an efficient way to do it. Here is my code:
def _remove_duplicate_loops(duplicate_loop):
loops=[]
for i in range(len(duplicate_loop)):
unique_el_list=[]
for j in range(len(duplicate_loop[i])):
if (duplicate_loop[i][j] not in unique_el_list):
unique_el_list.append(duplicate_loop[i][j])
loops.append(unique_el_list[:])
loops_set=[set(x) for x in loops]
unique_loop_dict={}
for k in range(len(loops_set)):
if (loops_set[k] not in list(unique_loop_dict.values())):
unique_loop_dict[k]=loops_set[k]
unique_loop_pos=list(unique_loop_dict.keys())
unique_loops=[]
for l in range(len(unique_loop_pos)):
unique_loops.append(duplicate_loop[l])
return unique_loops
from collections import OrderedDict
my_list = [[1, 2, 3, 1], [2, 3, 1, 2], [3, 2, 1, 3]]
seen_combos = OrderedDict()
for sublist in my_list:
unique_elements = frozenset(sublist)
if unique_elements not in seen_combos:
seen_combos[unique_elements] = sublist
my_list = seen_combos.values()
you could do it in a fairly straightforward way using dictionaries. but you'll need to use frozenset instead of set, as sets are mutable and therefore not hashable.
def _remove_duplicate_lists(duplicate_loop):
dupdict = OrderedDict((frozenset(x), x) for x in reversed(duplicate_loop))
return reversed(dupdict.values())
should do it. Note the double reversed() because normally the last item is the one that is preserved, where you want the first, and the double reverses accomplish that.
edit: correction, yes, per Steven's answer, it must be an OrderedDict(), or the values returned will not be correct. His version might be slightly faster too..
edit again: You need an ordered dict if the order of the lists is important. Say your list is
[[1,2,3,4], [4,3,2,1], [5,6,7,8]]
The ordered dict version will ALWAYS return
[[1,2,3,4], [5,6,7,8]]
However, the regular dict version may return the above, or may return
[[5,6,7,8], [1,2,3,4]]
If you don't care, a non-ordered dict version may be faster/use less memory.

Python append() vs. + operator on lists, why do these give different results?

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.

Categories

Resources