Please enumerate all kinds of comprehensions in Python 3 - python-3.x

So far, I've learned about
list
set
dictionary
generator
comprehensions. Are there any other iterables that can be ''comprehended''? I'm mostly interested in Python 3.

my_dict = {i:char for i,char in enumerate("Hello, world!")}
my_list = [i**2 for i in range(10)]
my_set = {i**2 for i in range(10)}
my_generator = (i**2 for i in range(10))
In terms of just comprehensions, there aren't any more that I'm aware of. You could of course use a list/generator comprehension within (say) a tuple constructor to create a (in this case) tuple. But that's not a generator per se

Related

Math-like way to define a set in Python: technical name [duplicate]

Can someone explain the last line of this Python code snippet to me?
Cell is just another class. I don't understand how the for loop is being used to store Cell objects into the Column object.
class Column(object):
def __init__(self, region, srcPos, pos):
self.region = region
self.cells = [Cell(self, i) for i in xrange(region.cellsPerCol)] #Please explain this line.
The line of code you are asking about is using list comprehension to create a list and assign the data collected in this list to self.cells. It is equivalent to
self.cells = []
for i in xrange(region.cellsPerCol):
self.cells.append(Cell(self, i))
Explanation:
To best explain how this works, a few simple examples might be instructive in helping you understand the code you have. If you are going to continue working with Python code, you will come across list comprehension again, and you may want to use it yourself.
Note, in the example below, both code segments are equivalent in that they create a list of values stored in list myList.
For instance:
myList = []
for i in range(10):
myList.append(i)
is equivalent to
myList = [i for i in range(10)]
List comprehensions can be more complex too, so for instance if you had some condition that determined if values should go into a list you could also express this with list comprehension.
This example only collects even numbered values in the list:
myList = []
for i in range(10):
if i%2 == 0: # could be written as "if not i%2" more tersely
myList.append(i)
and the equivalent list comprehension:
myList = [i for i in range(10) if i%2 == 0]
Two final notes:
You can have "nested" list comrehensions, but they quickly become hard to comprehend :)
List comprehension will run faster than the equivalent for-loop, and therefore is often a favorite with regular Python programmers who are concerned about efficiency.
Ok, one last example showing that you can also apply functions to the items you are iterating over in the list. This uses float() to convert a list of strings to float values:
data = ['3', '7.4', '8.2']
new_data = [float(n) for n in data]
gives:
new_data
[3.0, 7.4, 8.2]
It is the same as if you did this:
def __init__(self, region, srcPos, pos):
self.region = region
self.cells = []
for i in xrange(region.cellsPerCol):
self.cells.append(Cell(self, i))
This is called a list comprehension.

Python 3 list comprehension in list of lists to convert types

Consider the following list of lists:
list1 = [['1.1', '1.2', '1.3'], ['2.1', '2.2', '2.3'], ...]
To comprehend a list of strings to convert them to floats one could use
list1[0] = [float(i) for i in list1[0]]
But my attempt to comprehend a list of lists of floats didn't quite work:
list1 = [[float(j) for j in list1[i]] for i in list1]
due to
TypeError: list indices must be integers or slices, not list
Is there a way to do this sort of list comprehension without using loops explicitly?
[[float(j) for j in i] for i in list1]
shall do it

Get name of elements of a OrderedDict in pandas [duplicate]

With Python 2.7, I can get dictionary keys, values, or items as a list:
>>> newdict = {1:0, 2:0, 3:0}
>>> newdict.keys()
[1, 2, 3]
With Python >= 3.3, I get:
>>> newdict.keys()
dict_keys([1, 2, 3])
How do I get a plain list of keys with Python 3?
This will convert the dict_keys object to a list:
list(newdict.keys())
On the other hand, you should ask yourself whether or not it matters. It is Pythonic to assume duck typing -- if it looks like a duck and it quacks like a duck, it is a duck. The dict_keys object can be iterated over just like a list. For instance:
for key in newdict.keys():
print(key)
Note that dict_keys doesn't support insertion newdict[k] = v, though you may not need it.
Python >= 3.5 alternative: unpack into a list literal [*newdict]
New unpacking generalizations (PEP 448) were introduced with Python 3.5 allowing you to now easily do:
>>> newdict = {1:0, 2:0, 3:0}
>>> [*newdict]
[1, 2, 3]
Unpacking with * works with any object that is iterable and, since dictionaries return their keys when iterated through, you can easily create a list by using it within a list literal.
Adding .keys() i.e [*newdict.keys()] might help in making your intent a bit more explicit though it will cost you a function look-up and invocation. (which, in all honesty, isn't something you should really be worried about).
The *iterable syntax is similar to doing list(iterable) and its behaviour was initially documented in the Calls section of the Python Reference manual. With PEP 448 the restriction on where *iterable could appear was loosened allowing it to also be placed in list, set and tuple literals, the reference manual on Expression lists was also updated to state this.
Though equivalent to list(newdict) with the difference that it's faster (at least for small dictionaries) because no function call is actually performed:
%timeit [*newdict]
1000000 loops, best of 3: 249 ns per loop
%timeit list(newdict)
1000000 loops, best of 3: 508 ns per loop
%timeit [k for k in newdict]
1000000 loops, best of 3: 574 ns per loop
with larger dictionaries the speed is pretty much the same (the overhead of iterating through a large collection trumps the small cost of a function call).
In a similar fashion, you can create tuples and sets of dictionary keys:
>>> *newdict,
(1, 2, 3)
>>> {*newdict}
{1, 2, 3}
beware of the trailing comma in the tuple case!
list(newdict) works in both Python 2 and Python 3, providing a simple list of the keys in newdict. keys() isn't necessary.
You can also use a list comprehension:
>>> newdict = {1:0, 2:0, 3:0}
>>> [k for k in newdict.keys()]
[1, 2, 3]
Or, shorter,
>>> [k for k in newdict]
[1, 2, 3]
Note: Order is not guaranteed on versions under 3.7 (ordering is still only an implementation detail with CPython 3.6).
A bit off on the "duck typing" definition -- dict.keys() returns an iterable object, not a list-like object. It will work anywhere an iterable will work -- not any place a list will. a list is also an iterable, but an iterable is NOT a list (or sequence...)
In real use-cases, the most common thing to do with the keys in a dict is to iterate through them, so this makes sense. And if you do need them as a list you can call list().
Very similarly for zip() -- in the vast majority of cases, it is iterated through -- why create an entire new list of tuples just to iterate through it and then throw it away again?
This is part of a large trend in python to use more iterators (and generators), rather than copies of lists all over the place.
dict.keys() should work with comprehensions, though -- check carefully for typos or something... it works fine for me:
>>> d = dict(zip(['Sounder V Depth, F', 'Vessel Latitude, Degrees-Minutes'], [None, None]))
>>> [key.split(", ") for key in d.keys()]
[['Sounder V Depth', 'F'], ['Vessel Latitude', 'Degrees-Minutes']]
If you need to store the keys separately, here's a solution that requires less typing than every other solution presented thus far, using Extended Iterable Unpacking (Python3.x+):
newdict = {1: 0, 2: 0, 3: 0}
*k, = newdict
k
# [1, 2, 3]
Operation
no. Of characters
k = list(d)
9 characters (excluding whitespace)
k = [*d]
6 characters
*k, = d
5 characters
Converting to a list without using the keys method makes it more readable:
list(newdict)
and, when looping through dictionaries, there's no need for keys():
for key in newdict:
print key
unless you are modifying it within the loop which would require a list of keys created beforehand:
for key in list(newdict):
del newdict[key]
On Python 2 there is a marginal performance gain using keys().
Yes, There is a better and simplest way to do this in python3.X
use inbuild list() function
#Devil
newdict = {1:0, 2:0, 3:0}
key_list = list(newdict)
print(key_list)
#[1, 2, 3]
I can think of 2 ways in which we can extract the keys from the dictionary.
Method 1: -
To get the keys using .keys() method and then convert it to list.
some_dict = {1: 'one', 2: 'two', 3: 'three'}
list_of_keys = list(some_dict.keys())
print(list_of_keys)
-->[1,2,3]
Method 2: -
To create an empty list and then append keys to the list via a loop.
You can get the values with this loop as well (use .keys() for just keys and .items() for both keys and values extraction)
list_of_keys = []
list_of_values = []
for key,val in some_dict.items():
list_of_keys.append(key)
list_of_values.append(val)
print(list_of_keys)
-->[1,2,3]
print(list_of_values)
-->['one','two','three']
Beyond the classic (and probably more correct) way to do this (some_dict.keys()) there is also a more "cool" and surely more interesting way to do this:
some_dict = { "foo": "bar", "cool": "python!" }
print( [*some_dict] == ["foo", "cool"] ) # True
Note: this solution shouldn't be used in a develop environment; I showed it here just because I thought it was quite interesting from the *-operator-over-dictionary side of view. Also, I'm not sure whether this is a documented feature or not, and its behaviour may change in later versions :)
You can you use simple method like below
keys = newdict.keys()
print(keys)
This is the best way to get key List in one line of code
dict_variable = {1:"a",2:"b",3:"c"}
[key_val for key_val in dict_variable.keys()]

Python list comprehension - conditional for-loop

I've written some code like so which works fine and does what I want:
#!/usr/bin/env python3
myList = [[0], [1, 2], {'val': [3, 4, 5]}, [6]]
flat1 = []
for sublist in myList:
if type(sublist) is list:
for item in sublist:
flat1.append(item)
else:
for item in sublist['val']:
flat1.append(item)
print(flat1)
So it's a twist on the standard nested list flattening. The twist is that some nested items are not actually lists, but rather dictionaries with a 'val' (and we want the items in the 'val' list in those cases).
I'm trying to make it into a list comprehension. Here is what I've tried:
flat2 = [item for sublist in myList for item in sublist if type(sublist) is list else for item in sublist['val']]
print(flat2)
I get the following error with a caret pointing to the 'else'.
SyntaxError: invalid syntax
And yes what I've written into the list comprehension seems like nonsense and no doubt the compiler has no idea what I'm trying to do.
Is it possible to do what I'm trying to do with a list comprehension?
[item
for sublist in myList
for item in (sublist if type(sublist) is list else sublist['val'])
]
First off, I recommend against this approach. Why do you want to take what is already pretty readable and condense it so that it's unreadable?
flattened = [i for iterable in
(j if type(j) is list else j["val"] for j in myList)
for i in iterable]
Update after reading comment
One nice thing to do is to break out the list comprehension into two steps:
iterables = (j if type(j) is list else j["val"] for j in myList)
flattened = [i for iterable in iterables for i in iterable]
This is more readable -- and no less computationally efficient. Note the use of parentheses in iterables -- which makes it a generator that is lazily evaluated. That way, if myList is really long, you're still only reading through it once and you don't have to wait to read all the way through before proceeding.

When is map() necessary?

Given the following:
(I) a = map(function, sequence)
(II) a = [function(x) for x in sequence]
When would I need to use (I)? Why choose a map object over a list when the latter is subscriptable and IMO more readable?
Also, could someone explain line 6 of the following code (Python 3):
>>>import math
>>>a = map(int,str(math.factorial(100)))
>>>sum(a)
648
>>>sum(a)
0
Why is the sum of the map object changing?
When would I need to use (I)? Why choose a map object over a list when the latter is subscriptable and IMO more readable?
map was introduced in Python 1.0, while list comprehension was not introduced until Python 2.0.
For Python 2+, you never need to use one or the other.
Reasons for still using map could include:
preference. You prefer list comprehension, not everyone agrees.
familiarity. map is very common across languages. If Python's not your native language, "map" is the function you'll look up.
brevity. map is often shorter. Compare map and lambda f,l: [f(x) for x in l].
I is an iterator -- it creates a stream of values which then vanish. II is a list -- it lasts for a while and has lots of features, like len(mylist) and mylist[-3:].
The sum changes because the iterator vanishes after you use it.
Use lists and list comprehensions. If you process tons of data, then iterators (and generators, and generator comprehensions) are awesome, but they can be confusing.
Or, use an iterator and convert into a list for further processing:
a = list( map(int,str(math.factorial(100))) )
From the docs:
Apply function to every item of iterable and return a list of the results. If additional iterable arguments are passed, function must take that many arguments and is applied to the items from all iterables in parallel...
The sum changes to 0 because the iterator is iterated, so it becomes nothing. This is the same concept with .read() (Try calling x = open('myfile.txt'), and then type print x.read() twice.)
In order to preserve the iterable, surround it with list():
>>> import math
>>> a = map(int,str(math.factorial(100)))
>>> sum(a)
648
>>> sum(a)
0
>>> a = list(map(int,str(math.factorial(100))))
>>> sum(a)
648
>>> sum(a)
648
Example from the docs:
>>> seq = range(8)
>>> def add(x, y): return x+y
...
>>> map(add, seq, seq)
[0, 2, 4, 6, 8, 10, 12, 14]

Resources