6 ms·
But wait, there's more, you can send data back to the function! (Will be returned as the yield output) https://stackoverflow.com/questions/20579756/passing-val
by TrianguloY 3y ago
But wait, there's more, you can send data back to the function! (Will be returned as the yield output)
https://stackoverflow.com/questions/20579756/passing-value-to-yield-using-send#20579767 https://stackoverflow.com/questions/20579756/passing-value-t...
And don't forget "yield from" (same as yielding all values in a list, but keeps the original generator! You can send data back to the list if it is itself another generator!)
- noitpmeder 3y agoAnyone have good examples of how/when to actually use this? I've personally never interacted with or written a generator that expects to receive values.
- pizza 3y agoAnything with feedback control. Updating a priority queue's weights, adaptive caching, adaptive request limiting, etc. Ironically it looks like HN itself rate limited me the first time I tried to reply lol
- luckycharms810 3y agoThis is the basis of most older async frameworks (see: Tornado, Twisted). A while ago I put together a short talk on how to go from this feature -> a very basic version of Twisted's @inline_callback decorator. https://github.com/ltavag/async_presentation/tree/master https://github.com/ltavag/async_presentation/tree/master
- strunz 3y agoI actually had a great use case for this last week. Needed to flatten a list of nested dicts, e.g.: [ {"name": "/dev/loop0"}, {"name": "/dev/loop1"}, {"name": "/dev/loop2"}, { "name": "/dev/sda", "children": [ { "name": "/dev/sda1", "children": [{"name": "/dev/mapper/lubuntu--vg-root"}, {"name": "/dev/mapper/lubuntu--vg-swap_1"}], }, ], }, {"name": "/dev/sdb", "children": [{"name": "/dev/sdb1"}, {"name": "/dev/sdb2"}]}, {"name": "/dev/sdc", "children": [{"name": "/dev/sdc1"}, {"name": "/dev/sdc9"}]}, ] Wound up writing a recursive generator (with some help from #python on IRC): def flatten(items): for item in items: yield {k:v for k,v in item.items() if k != 'children'} if 'children' in item: yield from flatten(item['children']) which results in: [{'name': '/dev/loop0'}, {'name': '/dev/loop1'}, {'name': '/dev/loop2'}, {'name': '/dev/sda'}, {'name': '/dev/sda1'}, {'name': '/dev/mapper/lubuntu--vg-root'}, {'name': '/dev/mapper/lubuntu--vg-swap_1'}, {'name': '/dev/sdb'}, {'name': '/dev/sdb1'}, {'name': '/dev/sdb2'}, {'name': '/dev/sdc'}, {'name': '/dev/sdc1'}, {'name': '/dev/sdc9'}]
- TrianguloY 3y agoI see your function and "yield" (pun definitely intended) the following: def flatten(children=[], **other): if other: yield other for child in children: yield from flatten(**child)
- strunz 3y agoThat's pretty brilliant to use `children` as the keyword name, thanks!
- noitpmeder 3y agoThanks for the example, but I was more looking for something that uses "generator.send(...)". I definitely agree that yielding items out of generators is extremely useful, but not so sure on examples of generators that are sent values.
- noman-land 3y agoI am a python noob and this is going to take me some time to process.
- contravariant 3y agoBest way to think about it is that a generator can throw some questions back to the caller. It always looks a bit messy though. question_bank={'1+1' : '2', '2+3' : '5'} def Quiz(): for question, correct_answer in question_bank.items(): answer = yield question if answer == correct_answer: print('Correct!') else: print('Wrong.') yield 'Finished!' question = Quiz() q = next(question) while q != 'Finished!': q = question.send(input(q))