0

I created my own iterator (to learn how they work) as follows

class Reverse():
    def __init__(self, word):
        self.word = word
        self.index = len(word)
    def __iter__(self):
        return self
    def __next__(self):
        self.index -=1
        if self.index < 0:
            raise StopIteration
        return self.word[self.index]

print (char for char in Reverse("word"),end="")

I know I can say:

rev = Reverse("word")
for char in rev:
    print(char, end="")

but I was hoping to be able to do it in a single line

print (char for char in Reverse("word"),end="")

This doesn't work and raises an error. If I remove the end="" it prints out a generator object. Surely by including a for loop in the print statement it should iterate through my generator object and print each item? Why does this not happen

4 Answers 4

2

A generator is a lazy iterator. When you use a for loop, you are manually exhausting the generator. When you print it out in a single line, you are not exhausting it by iterating.

You can unpack the generator to exhaust it and get all of the values:

print(*(char for char in Reverse('word')), sep='')

I’ve changed end for sep as you are doing everything in 1 print call so want to separate each ‘argument’ (character) with no space.

You can also do the following:

print(*Reverse('word'), sep='')

As Reverse is already an iterator, you are able to exhaust it.

Sign up to request clarification or add additional context in comments.

Comments

1

Surely by including a for loop in the print statement it should iterate through my generator object and print each item?

No, it will print the string representation of a generator object.

If you want to output what this object generates, you can use a starred expression:

print(*(char for char in Reverse("word")),end="")

This is because the for loop in a generator expression isn't actually executed at the instantiation of the generator object, and that's the whole point of generators: you can have an infinite generator and still be able to pass it around as a regular value and consume finite chunks of it, all that without having infinite amounts of memory.

Comments

1

Why not like this?

print(''.join([char for char in Reverse("word")]))

5 Comments

The [ ] create an unnecessary list, and you also do not have to iterate manually. Just do print(''.join(Reverse("word")))
@DeepSpace it's faster to join the list comprehension than a genex. I need to dig the reference out, but the genex will be expanded before join can work
@roganjosh It sounds a bit weird but I'll wait for the reference. Anyway, for longer "words" I'm pretty sure the overhead of the list comp will be more noticeable.
@DeepSpace more-specifically, this but I guess you've probably already followed the rabbit hole and found that :)
1
x = my_objects.objects.all() # x, turns to a QuerySet

for i in range(len(x)):
    print(x[i])

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.