If you want to create a literal new list with a bunch of new values then you're right. There is no reason to use the list constructor, you should use the literal notation:
my_list = ['a', 'b', 'c']
In fact, it is impossible to create a new list with a bunch of values using the constructor, you can only use it to transform iterables into their list representation:
my_tuple = ('a', 'b', 'c') # literal notation to create a new tuple
my_list = list(my_tuple) # this is what you actually did in your first example
You can use the other iterable constructors like set and dict in a similar way. They are not used to create new objects, but transform existing ones into the type they describe.
`list()` constructor and `__len__` method
How to pass a list in constructor?
Creating a list of objects in Python constructor - Stack Overflow
python - List Constructor: How does it really work in the following code? - Stack Overflow
Videos
If you want to create a literal new list with a bunch of new values then you're right. There is no reason to use the list constructor, you should use the literal notation:
my_list = ['a', 'b', 'c']
In fact, it is impossible to create a new list with a bunch of values using the constructor, you can only use it to transform iterables into their list representation:
my_tuple = ('a', 'b', 'c') # literal notation to create a new tuple
my_list = list(my_tuple) # this is what you actually did in your first example
You can use the other iterable constructors like set and dict in a similar way. They are not used to create new objects, but transform existing ones into the type they describe.
Perhaps we want to convert a Map or Set into a list. We would pass it into the constructor.
mylist = list(myset)
New in Python Please guide
Want to write simple class for Matrix addition using concept of operator overloading
list is a built-in class in Python. There are three main ways of constructing a list.
The first way is by calling the "constructor", or list.__call__, usually with list(...). The constructor accepts any iterable and initializes a list that refers to all of its elements. In your first example, you pass in the tuple of strings ("apple", "banana", "cherry"). The result of the assignment is that a new list object is bound to the name thislist.
The second way is by enclosing a comma-separated collection in square brackets. The result of thislist = ["apple", "banana", "cherry"] is that a new list object equal to the one in the first example is bound to the name thislist. This notation is possible because the type list is so integral to the Python language that the interpreter recognizes this syntax. Other examples of similarly fundamental data structure types are set (initialized by {'a', 'b', 'c'}), dict (initialized by {'a': 1, 'b': 2, 'c': 3}) and tuple (initialized by ('a', 'b', 'c')).
The third way to construct a list is through a comprehension. It's sort of a hybrid of the first two ways because it allows you to use an iterable, rather than a literal sequence, inside square brackets. An example of a list comprehension would be something like:
thislist = [x for x in ("apple", "banana", "cherry")]
In general, a comprehension works by constructing an empty list and appending the elements of the generator expression in the brackets. It's roughly equivalent to
thislist = [] # or thislist = list()
for x in ("apple", "banana", "cherry"):
thislist.append(x)
listandtupleare both built in python classes.
Let's first talk about Lists
Lists are sequences and are used to store collections of homogeneous items.
The list constructor is:
list([iterable])
You can construct List in several ways:
- With a pair of square brackets which denotes the empty list. For Example:
[] - With square brackets and items separated with commas. For Example:
[a, b, c] - With the help of a list comprehension. For Example:
[x for x in iterable] - With the help of type constructor. For Example:
list()orlist(iterable)
The constructor
list(iterable)builds a list whose items are the same and in the same order as iterable’s items.
Here, iterable may be either a sequence or an object that supports iteration, or an iterator object.
If iterable is already a list: A copy of the list is returned
For example:
>>> list('abc')
['a', 'b', 'c']
>>> list( (1, 2, 3) ) # Next let's understand what a tuple is
[1, 2, 3]
Now let's talk about Tuples
Tuples are sequences which are used to store collections of heterogeneous data.
The tuple constructor is:
tuple([iterable])
You can create tuples in many ways:
- With a pair of parentheses to denote the empty tuple. For Example:
() - With many items separated by commas. For Example:
(a, b, c) - With a trailing comma for a singleton tuple. For Example:
a,or(a,) - With the help of
tuple()constructor. For Example:tuple()ortuple(iterable)
This tuple(iterable) constructor builds a tuple with identical items and in same order as iterable’s items. The iterable can be a sequence or an iterator object.
If iterable is already a tuple it's copy will be returned.
For Example:
>>> tuple('abc')
('a', 'b', 'c')
>>> tuple( [1, 2, 3] )
(1, 2, 3)
>>> tuple
()
>>> t = 1,2,3
>>> t
(1, 2, 3)
Note that it is actually the comma which makes a tuple, not the parentheses. The parentheses are optional, except in the empty tuple case, or when they are needed to avoid syntactic ambiguity.
Taking your question as an example:
You want to give a tuple to create a list. So to identify that the input to the list constructor is a tuple it is need to be enclosed in parentheses.
thislist = list(("apple", "banana", "cherry"))
Here ("apple", "banana", "cherry") will create a tuple implicitly. Then this tuple ("apple", "banana", "cherry") is the iterable input for the list constructor and returns an list object.
>>> type(("apple", "banana", "cherry"))
<class 'tuple'>
When you provide ["apple", "banana", "cherry"], an object of list is created implicitly and returned.
>>> type(["apple", "banana", "cherry"])
<class 'list'>
To answer your question, there is no direct equivalent to the cons that you would usually find in what are called "functional" languages (lisp, OCaml, Haskell, etc.)
That's because there are two competing models to represent lists of elements in programming languages.
Linked lists
The one you seem to be familiar with is called a linked list.
A linked list is composed of cons-cells that each contain two references :
- the first one toward an element of the list and is called head
- the other towards the next cons-cell in the list and is the tail
Because lists are rarely infinite, the last const cell would usually point towards a special value, the empty list, sometimes called nil.
If you wanted to save the list in a variable for future reference, you would keep a reference towards the first cons-cell.
Here's a visual representation from Wikipedia.
In this model, every list is necessarily constructed by adding elements to the front by creating a new cons-cell, pointing to the new element as its head and to the previously constructed sublist as its tail. This is why the cons operator is sometimes called the list constructor.
Arrays
This is the model usually preferred by imperative languages such as Python. In this model, a list is just a reference to a range in memory.
Let's suppose you create a list just like so :
l = [1, 2, 3]
Whenever you create a list, Python will assign to it a small range of memory in which to store the elements, with a bit of extra space just in case you want to add elements later. To store it, you would simply store a reference to the first element, and to the size of the memory range, just like so :
l <-- your variable
| ___ ___ ___ ___ ___ ___ ___ ___ ___
|-> | | | | | | | | | |
| 1 | 2 | 3 | | | | | | |
|___|___|___|___|___|___|___|___|___|
If you decide to add an element at the end of the list, you can use append
l.append(4)
Resulting in the following list :
___ ___ ___ ___ ___ ___ ___ ___ ___
| | | | | | | | | |
| 1 | 2 | 3 | 4 | | | | | |
|___|___|___|___|___|___|___|___|___|
Now, let's say you forgot an initial 0, and you now wish to add it to the front. You could really well use the insert method (with an insert position of 0) :
l.insert(0, 0)
But there's no space at the beginning of the list ! Python has no choice but to take each and every element, and copy them one at a time in the spot on the direct right :
___ ___ ___ ___ ___ ___ ___ ___ ___
| | | | | | | | | |
| 1 | 2 | 3 | 4 | | | | | |
|___|___|___|___|___|___|___|___|___|
| | |__ |___
| |___ | | First, Python has to copy the four elements
|___ | | | one space to the right
___ _\/ _\/ \/_ _\/ ___ ___ ___ ___
| | | | | | | | | |
| | 1 | 2 | 3 | 4 | | | | |
|___|___|___|___|___|___|___|___|___|
Only then can it insert the 0 at the beginning
___ ___ ___ ___ ___ ___ ___ ___ ___
| | | | | | | | | |
| 0 | 1 | 2 | 3 | | | | | |
|___|___|___|___|___|___|___|___|___|
It may not seem like much for such a small array, but imagine your array is much bigger, and you repeat this operation many times : you would spend so much time building your list !
That is why you won't find a list constructor in languages using arrays for their lists like Python.
Diving further : why the two different models?
You may now be wondering why different languages would prefer different list models, and if one of the two models is superior.
It's because these two data structures have different performance in different contexts. Two examples :
Accessing an element in the middle
Let's suppose you want to get the fifth element of the list.
In the linked list you would need to get :
- the first cons cell
- then the tail of this cell to get the second element
- then the tail of this cell to get the third element
- then the tail of this cell to get the fourth element
- and finally the tail of this cell to get the fifth element
You would thus have to go through 5 references !
With an array, that's much simpler : you know the reference of the first element. You just need to access the reference 4 spots on the right, given the elements are all in a contiguous memory range !
If you need to access random elements of a very large list a great many times, arrays are thus much better.
Inserting an element in the middle
Imagine you now want to insert an element in the middle.
With a linked list :
- you locate the cons cell corresponding to the last element before the insertion point.
- you create a new cons cell, with a head pointing to the element you want to add and the same tail as the cons cell you just located.
- you can now change the tail of this cell to point to the newly created cell.
With an array, just as when adding an element in the middle, you will need to copy every element to the right of the insertion point one space to the right !
In this situation, that's the linked list that is clearly superior.
Some are suggesting that you do:
a = 1
b = [2, 3, 4, 5]
c = [a] + b
Which will work provided that b is of type list. However, often you'll find yourself working with an object that is either a list or a tuple or (insert your favorite iterable object here). In that case, it might be more worth your while to do:
a = 1
b = (2, 3, 4, 5)
c = [a]
c.extend(b)
This makes the whole thing agnostic to the type of b (this allows your code to be more "ducky", which can be kind of nice). . .
Of course, there are other options as well. . . For example, You could choose to reach for itertools:
import itertools
a = 1
b = [2, 3, 4, 5]
lazy_c = itertools.chain([a], b)
Again we have the benefit of not caring what type of iterable b is, and we pick up a side benefit of iterating lazily -- We won't make a new list or tuple. We'll just make an object that will yield the same thing when you're iterating over it. This can save memory (and sometimes cycles for your CPU), but can also have un-intended consequences if b is also a sort of generator-like object that is being iterated over elsewhere at the same time (which doesn't happen by accident very often).