Debugging Kubernetes

23 Jul 2024

Helpful tips for debugging applications running in k8s

build/k8s.png

Handling multiple errors in Rust iterator adapters

17 Dec 2023

Approaches for handling multiple errors within iterator adapters

build/rust.png

Better FastAPI Background Jobs

29 Aug 2022

A more featureful background task runner for Async apps like FastAPI or Discord bots

build/fastapi_logo.png

Useful Linux Examples

21 Dec 2021

A plethora of helpful tips for working in Linux

build/bash_logo.png
Continue to all blog posts

Generators

WIP post

Generators in python are often sited as one of the useful things to learn, though people leave out a very interesting aspect though, the send method, but more on that later…

Basics

How to create generators:

Way #1

Implement the __next__ method on a class

class MyGenerator:
    def __init__(self):
        self.inner_list = [1, 2, 3]

    def __next__(self):
        try:
            return self.inner_list.pop(0)
        except IndexError:
            return None
Way #2

Using yield in a function

def my_gen():
    list_of_i = [0, 1]
    for i in list_of_i:
        yield i
Way #3

Generator comprehension can be created in a very similar way to list comprehension just swapping the outer [...] brackets for (...) brackets

gen_comp = (str(i) for i in range(10))

using generators

my_gen.__next__()

next(my_gen)

for i in my_gen

def my_gen():
    list_of_i = [0, 1]
    for i in list_of_i:
        yield i

x = my_gen()

print('First Call:', x.__next__())
print('Second Call:', next(x))
try:
    print('Third Call (will fail)')
    next(x)
except StopIteration:
    print('Catch StopIteration error')

returns:

First Call: 0
Second Call: 1
Third Call (will fail)
Catch StopIteration error

Lets break down what’s happening there…

Pros & Cons

The Send Method

yield is more that just magic pixie dust to sprinkle on return’s to make them better in some ways though!

Something that is often left out of the explanation of yield is that not only is it a way to exit from a “function”, it’s also an entrypoint!

Checkout this example:

def my_gen():
    list_of_i = [0, 1]
    y = 'will be changed'
    for i in list_of_i:
        y = yield i
        print(f'After yield, when i={i}, y={y} (type:{type(y)})')

x = my_gen()

print('First Call:', next(x))
print('Second Call:', x.send('new_y_value'))
try:
    print('Third Call (will fail)')
    next(x)
except StopIteration:
    print('Catch StopIteration error')

which returns:

First Call: 0
After yield, when i=0, y=new_y_value (type:<class 'str'>)
Second Call: 1
Third Call (will fail)
After yield, when i=1, y=None (type:<class 'NoneType'>)
Catch StopIteration error

Lets break down what’s happening there…

Yield From

yield from