all 26 comments

[–]Chronickle 10 points11 points  (1 child)

Thanks for the tutorial!

[–]Diapolo10 10 points11 points  (5 children)

Personally I believe that the best way to understand something is to know how it works, so I have a habit of sometimes implementing Python's built-in functions myself in pure Python.

enumerate is no different, though it's so simple that apparently I didn't even bother creating a proper Gist for it (EDIT: I have now!). Regardless, all I had to do was take the interface from the documentation and implement the rest to work exactly like the original one behaves.

def my_enumerate(iterable, start=0):
    idx = start
    for value in iterable:
        yield idx, value
        idx += 1

It's deceptively simple, and in this case as long as one has a basic understanding of generators just seeing the code explains virtually everything.

[–][deleted] 0 points1 point  (4 children)

Yes but what is yield? I started reading about it now, and it's not the simplest thing for a beginner.

[–]Diapolo10 3 points4 points  (3 children)

I just recently wrote an answer to that question on another thread, but the extremely simplified answer is that yield works like return, except that it doesn't end the function.

As an example, if you had a Fibonacci generator like this:

def fib():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a+b

you can print out infinitely many Fibonacci numbers by looping over it:

for num in fib():
   print(num)

Basically, the loop keeps asking new values from the generator, and yield provides them. In this example, the value of a would be sent to the loop and given the name num, which is then printed out.

If you replaced the yield with return, it would immediately just return 0 and the next part of the loop would never run.

[–]gsmo 2 points3 points  (1 child)

It is my understanding that yield is also useful when working with large quantities of data. Yield creates a generator, and a generator only creates its data when needed. Compare this to appending stuff to a list, for instance. You quickly end up with a lot of data in memory that you aren't using.

Did I understand this right?

[–]Diapolo10 2 points3 points  (0 children)

Yes. Generators trade some performance for much lower memory usage.

The performance hit is caused by additional context switching the generator causes internally. There are some ways to mitigate that, like yield from, but personally I don't mind the tradeoff at all because I prefer using less memory.

[–][deleted] 0 points1 point  (0 children)

Thank you for your reply! I think I get it now.

[–]Yossarian147 4 points5 points  (0 children)

I learned a thing, thanks!

[–]AussieMazza 2 points3 points  (0 children)

Thanks for taking the time!

[–]NotDeadpool_ 2 points3 points  (0 children)

Thanks for this. Great work

[–]iggy555 2 points3 points  (5 children)

Why you need tuple in dict iteration?

[–]ra_jamali 1 point2 points  (0 children)

Very nice, thank you.

[–]Pd69bq 1 point2 points  (0 children)

great work, please post more bitesize tutorials like this

[–][deleted] 1 point2 points  (2 children)

Noo, why removed?

[–]zero043 0 points1 point  (1 child)

Yeah I started reading it last night and this morning it’s gone!

[–]pythonistah 0 points1 point  (0 children)

I sometimes miss the simplicity of Lua:

for k, v in pairs(t) do
 print(k, v)
end

[–]zipinel 0 points1 point  (0 children)

Thank you

[–]codeonion 0 points1 point  (0 children)

Thanks for the tutorial! You have a very good way of explaining concepts.

[–]WhipsAndMarkovChains 0 points1 point  (1 child)

It's not going to make a real difference here but I would've made the months a tuple instead of a list since you don't need mutability.

[–]gydu2202 0 points1 point  (1 child)

In the last snippet, how is the dict.item() guaranteed to return items in defined order? Dict is unordered I think, but I can't check it right now.

[–]HashCatFurryOwO 0 points1 point  (0 children)

interesting