Python Forum
Comprehending a list comprehension! - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: Comprehending a list comprehension! (/thread-5952.html)



Comprehending a list comprehension! - alidaf - Oct-30-2017

I have been given some example code that captures BLE broadcasts from beacons but there's a line that is really confusing me:

data = [b for b in device.data]
device.data is a list that contains BLE broadcast data from the bluetooth.get_adv() MicroPython function. It can hold up to 16 devices.

I just don't understand the syntax. b is not used anywhere and I don't get what b for b is actually doing, especially since it isn't defined anywhere.

I think this is a 'list comprehension' but the explanations I have found are addling my noodle. How would this expand into a normal, sane 'for loop'?


RE: Comprehending a list comprehension! - wavic - Oct-30-2017

If device.data is a list, data = [b for b in device.data] is meaningless. It's the same as data = device.data. Anyway! The whole [b for b in device.data] means "append to data an element ( b) for any element in the list ( device.data ). It the same as:

for b in device.data:
    data.append(b)
See https://python-forum.io/Thread-Comprehension-Expressions


RE: Comprehending a list comprehension! - buran - Oct-30-2017

(Oct-30-2017, 10:51 AM)wavic Wrote: If device.data is a list, data = [b for b in device.data] is meaningless. It's the same as data = device.data.

That is not true. List is mutable, thus is you just do data = device.data change in data would affect also device.data and vice versa.

>>> my_list = [1, 2, 3]
>>> a_list = [x for x in my_list]
>>> b_list = my_list
>>> my_list[0] = 100
>>> my_list
[100, 2, 3]
>>> a_list # still has the original values
[1, 2, 3]
>>> b_list
[100, 2, 3] # has new value at index 0, same as my_list
>>>
an alternative to list comprehension for creating a copy would be list slicing
data = device.data[::]



RE: Comprehending a list comprehension! - wavic - Oct-30-2017

You are right. data = device.data will create just another pointer to the same address.


RE: Comprehending a list comprehension! - metulburr - Oct-30-2017

Quote:I just don't understand the syntax. b is not used anywhere and I don't get what b for b is actually doing, especially since it isn't defined anywhere.

list comps can get unwieldy to the point of doing more harm than good, but this is the most simple.


[b for b in device.data]
There are two parts here. The second is the actual for loop header, the first is what is being put into the list on each iteration. Assuming device.data was a list of stringed ints, you could convert these by modifying the first section as such
[int(b) for b in device.data]
The result would be a list of ints, instead of strings.

On the same token if you wanted to restrict what is in the new list
[int(b) for b in device.data if b.startswith('o')]
which would look like
[int(b) for b in device.data if b.startswith('o')]
This would be the equivalent of adding an if condition into the for loops block. This would create a third section in the list comp that you would have to identify.
The first section is what is being added to the list, the second is the for loop header, and the 3rd is the restrictions. You could kind of read it from section 2, section 3, then section 1.
This would be the drawn out for loop
lst = []
for b in device.data:
    if b.startswith('o'):
        lst.append(int(b))
You can make it more complicated, but at times depending on how much more complicated, it might not be worth it as it takes too long for humans to decipher.

An example of the same as previous, but one you might want to split out into a regular for loop
[x.id for x in self.db.query(schema.allPostsUuid).execute(timeout = 20) if x.type == "post" and x.deleted is not False]

You can of course split it out within, but then at that point is it worth it?

all_posts_uuid_query = self.db.query(schema.allPostsUuid)
all_posts_uuid_list = all_posts_uuid_query.execute(timeout=20)
all_uuid_list = [
    x.id 
    for x in all_posts_uuid_list 
    if (
        x.type == "post" 
        and 
        not x.deleted  # <-- if you don't care about NULLs / None
    )
]