I am trying to do something like this:
my_list = list((1,2,3)).insert(0,0)
Is there a way to do that in one expression?
P.S. I am not trying to be economic with my lines, I'm just curious is that possible and how would one do it in python.
If you are on python 3.8+ this is doable
>>> (my_list:=list((1,2,3))).insert(0,0)
>>> my_list
[0, 1, 2, 3]
One slightly naive way is the following:
a = [0] + list((1,2,3))
.insert() (same as .append(), .extend(), etc) modifies the list but don't actually return anything, that's why you can't use them in a chained operation. See the answer here about why this happens as a Python design choice.
Related
I'm trying to figure out what is the pythonic way to unpack an iterator inside of a list.
For example:
my_iterator = zip([1, 2, 3, 4], [1, 2, 3, 4])
I have come with the following ways to unpack my iterator inside of a list:
1)
my_list = [*my_iterator]
2)
my_list = [e for e in my_iterator]
3)
my_list = list(my_iterator)
No 1) is my favorite way to do it since is less code, but I'm wondering if this is also the pythonic way. Or maybe there is another way to achieve this besides those 3 which is the pythonic way?
This might be a repeat of Fastest way to convert an iterator to a list, but your question is a bit different since you ask which is the most Pythonic. The accepted answer is list(my_iterator) over [e for e in my_iterator] because the prior runs in C under the hood. One commenter suggests [*my_iterator] is faster than list(my_iterator), so you might want to test that. My general vote is that they are all equally Pythonic, so I'd go with the faster of the two for your use case. It's also possible that the older answer is out of date.
After exploring more the subject I've come with some conclusions.
There should be one-- and preferably only one --obvious way to do it
(zen of python)
Deciding which option is the "pythonic" one should take into consideration some criteria :
how explicit,
simple,
and readable it is.
And the obvious "pythonic" option winning in all criteria is option number 3):
list = list(my_iterator)
Here is why is "obvious" that no 3) is the pythonic one:
Option 3) is close to natural language making you to 'instantly'
think what is the output.
Option 2) (using list comprehension) if you see for the first time
that line of code will take you to read a little bit more and to pay
a bit more attention. For example, I use list comprehension when I
want to add some extra steps(calling a function with the iterated
elements or having some checking using if statement), so when I see a
list comprehension I check for any possible function call inside or
for any if statment.
option 1) (unpacking using *) asterisk operator can be a bit confusing
if you don't use it regularly, there are 4 cases for using the
asterisk in Python:
For multiplication and power operations.
For repeatedly extending the list-type containers.
For using the variadic arguments. (so-called “packing”)
For unpacking the containers.
Another good argument is python docs themselves, I have done some statistics to check which options are chosen by the docs, for this I've chose 4 buil-in iterators and everything from the module itertools (that are used like: itertools.) to see how they are unpacked in a list:
map
range
filter
enumerate
itertools.
After exploring the docs I found: 0 iterators unpacked in a list using option 1) and 2) and 35 using option 3).
Conclusion :
The pythonic way to unpack an iterator inside of a list is: my_list = list(my_iterator)
While the unpacking operator * is not often used for unpacking a single iterable into a list (therefore [*it] is a bit less readable than list(it)), it is handy and more Pythonic in several other cases:
1. Unpacking an iterable into a single list / tuple / set, adding other values:
mixed_list = [a, *it, b]
This is more concise and efficient than
mixed_list = [a]
mixed_list.extend(it)
mixed_list.append(b)
2. Unpacking multiple iterables + values into a list / tuple / set
mixed_list = [*it1, *it2, a, b, ... ]
This is similar to the first case.
3. Unpacking an iterable into a list, excluding elements
first, *rest = it
This extracts the first element of it into first and unpacks the rest into a list. One can even do
_, *mid, last = it
This dumps the first element of it into a don't-care variable _, saves last element into last, and unpacks the rest into a list mid.
4. Nested unpacking of multiple levels of an iterable in one statement
it = (0, range(5), 3)
a1, (*a2,), a3 = it # Unpack the second element of it into a list a2
e1, (first, *rest), e3 = it # Separate the first element from the rest while unpacking it[1]
This can also be used in for statements:
from itertools import groupby
s = "Axyz123Bcba345D"
for k, (first, *rest) in groupby(s, key=str.isalpha):
...
If you're interested in the least amount of typing possible, you can actually do one character better than my_list = [*my_iterator] with iterable unpacking:
*my_list, = my_iterator
or (although this only equals my_list = [*my_iterator] in the number of characters):
[*my_list] = my_iterator
(Funny how it has the same effect as my_list = [*my_iterator].)
For the most Pythonic solution, however, my_list = list(my_iterator) is clearly the clearest and the most readable of all, and should therefore be considered the most Pythonic.
I tend to use zip if I need to convert a list to a dictionary or use it as a key-value pair in a loop or list comprehension.
However, if this is only for illustration to create an iterator. I will definitely vote for #3 for clarity.
I have a list of strings that print out just fine using a normal loop:
for x in listing:
print(x)
I thought it should be pretty simple to use a lambda to reduce the loop syntax, and kickstart my learning of lambdas in Python (I'm pretty new to Python).
Given that the syntax for map is map(function, iterable, ...) I tried:
map(lambda x: print(x), listing)
But this does not print anything out (it also does not produce an error). I've done some searching through material online but everything I have found to date is based on Python 2, namely mentioning that with Python 2 this isn't possible but that it should be in Python 3, without explicitly mentioning how so.
What am I doing wrong?
In python 3, map returns an iterator:
>>> map(print, listing)
<map object at 0x7fabf5d73588>
This iterator is lazy, which means that it won't do anything until you iterate over it. Once you do iterate over it, you get the values of your list printed:
>>> listing = [1, 2, 3]
>>> for _ in map(print, listing):
... pass
...
1
2
3
What this also means is that map isn't the right tool for the job. map creates an iterator, so it should only be used if you're planning to iterate over that iterator. It shouldn't be used for side effects, like printing values. See also When should I use map instead of a for loop.
I wouldn't recommend using map here, as you don't really care about the iterator. If you want to simplify the basic "for loop", you could instead use str.join():
>>> mylist = ['hello', 'there', 'everyone']
>>> '\n'.join(mylist)
hello
there
everyone
Or if you have a non-string list:
>>> mylist = [1,2,3,4]
>>> '\n'.join(map(str, mylist))
1
2
3
4
I am reading Joel Grus's data science from scratch book and found something a bit mysterious. Basically, in some sample code, he wrote
a = [1, 2 ,3 ,4]
xs = [i for i,_ in enumerate(a)]
Why would he prefer to do this way? Instead of
xs = range(len(a))
Answer: personal preference of the author. I find
[i for i, _ in enumerate(xs)]
clearer and more readable than
list(range(len(xs)))
which feels clunky to me. (I don't like reading the nested functions.) Your mileage may vary (and apparently does!).
That said, I am pretty sure I didn't say not to do the second, I just happen to prefer the first.
Source: I am the author.
P.S. If you're the commenter who had no intention of reading anything I write about Python, I apologize if you read this answer by accident.
I looked at the code available on github and frankly, I do not see any other reason for this except the personal preference of the author.
However, the result needs to be a list in places like this:
indexes = [i for i, _ in enumerate(data)] # create a list of indexes
random.shuffle(indexes) # shuffle them
for i in indexes: # return the data in that order
yield data[i]
Using bare range(len(data)) in that part on Python 3 would be wrong, because random.shuffle() requires a mutable sequence as the argument, and the range objects in Python 3 are immutable sequences.
I personally would use list(range(len(data))) on Python 3 in the case that I linked to, as it is guaranteed to be more efficient and would fail if a generator/iterator was passed in by accident, instead of a sequence.
Without being the author, I would have to guess, but my guess is that it's for Python 2 and 3 compatibility.
In Python 2:
>>> a = [1,2,3,4]
>>> xs = range(len(a))
>>> xs
[0, 1, 2, 3]
>>> type(xs)
<type 'list'>
In Python 3:
>>> a = [1,2,3,4]
>>> xs = range(len(a))
>>> xs
range(0, 4)
>>> type(xs)
<class 'range'>
Now, that doesn't make a difference when you're directly iterating over the range, but if you're planning to use the index list for something else later on, the author may feel that the enumerate is simpler to understand than list(range(len(a)))
Both are ok.
When I started coding in python I was more list(range(len(a))) .
Now I am more in pythonic way .
Both are readable.
While I was going through Google Python Class Day 1 Part 2 at 14:20 - 14:30 Guy says "do not use list.sort". Also he mentioned that "Dinosaurs use that!" (i.e. it's an old way of doing sorting). But he did not mention the reason.
Can anyone tell me why we should not use list.sort?
Because list.sort() will do an in-place sorting. So this changes the original list. But sorted(list) would create a new list instead of modifying the original.
Example:
>>> s = [1,2,37,4]
>>> s.sort()
>>> s
[1, 2, 4, 37]
>>> s = [1,2,37,4,45]
>>> sorted(s)
[1, 2, 4, 37, 45]
>>> s
[1, 2, 37, 4, 45]
I think it is very opinion based, sometimes you need to change an original list and you use .sort(), sometimes you don't need to change it, and you use sorted()
In general, it isn't bad to use .sort()
From https://wiki.python.org/moin/HowTo/Sorting:
You can also use the list.sort() method of a list. It modifies the
list in-place (and returns None to avoid confusion). Usually it's less
convenient than sorted() - but if you don't need the original list,
it's slightly more efficient.
Many people prefer not changing the state of variables (look up the advantages of immutable values/data structures), and so would prefer not to modify the original list like list.sort does.
Consider:
fooList = [1, 2, 3, 4] # Ints for example only, in real application using objects
for foo in fooList:
if fooChecker(foo):
remove_this_foo_from_list
How is the specific foo to be removed from the list? Note that I'm using ints for example only, in the real application there is a list of arbitrary objects.
Thanks.
Generally, you just don't want to do this. Instead, construct a new list instead. Most of the time, this is done with a list comprehension:
fooListFiltered = [foo for foo in fooList if not fooChecker(foo)]
Alternatively, a generator expression (my video linked above covers generator expressions as well as list comprehensions) or filter() (note that in 2.x, filter() is not lazy - use a generator expression or itertools.ifilter() instead) might be more appropriate (for example, a large file that is too big to be read into memory wouldn't work this way, but would with a generator expression).
If you need to actually modify the list (rare, but can be the case on occasion), then you can assign back:
fooList[:] = fooListFiltered
Iterate over a shallow copy of the list.
As you can't modify a list while iterating over so you need to iterate over a shallow copy of the list.
fooList = [1, 2, 3, 4]
for foo in fooList[:]: #equivalent to list(fooList), but much faster
if fooChecker(foo):
fooList.remove(foo)
Use filter:
newList = list(filter(fooChecker, fooList))
or
newItems = filter(fooChecker, fooList))
for item in newItems:
print item # or print(item) for python 3.x
http://docs.python.org/2/library/functions.html#filter