8

Possible Duplicate:
The Python yield keyword explained

Okay, I've probably phrased the question badly but this is the situation I have.

I have this line of code in Python 2.7 which I'm trying to understand:

yield (padding_zeros + number_string).encode("ascii")

In this line of code, padding_zeros is a string of a variable number of '0's and number_string is a number in the form of a string which can be any number between 0 to, say 10000.

I'm pretty confident that the .encode("ascii") just converts the output of yield to ascii.

What I'm completely at sea about is what the yield (padding_zeros + number_string) does.

I know it initiates a generator but I've spent a lot of time searching online and reading up on the syntax but I still can't work out what the generator actually does. It doesn't help that this is my first time looking at python (my ultimate aim is to convert this code to C#).

So, basically, please could someone explain to me what this line of code does? Does it just add the two strings together or does it do something a bit more complicated?

For further context, this is the block that that line of code appears in:

for current_length in range(4, max_length + 1):
    for i in range(0, pow(10, current_length)):
        number_string = str(i)
        padding_zeros = "0" * (current_length - len(number_string))
        yield (padding_zeros + number_string).encode("ascii")

(max_length being exactly what it sounds like - a number indicating the maximum length of something)

Thanks in advance for any and all answers (even if they're telling me not to be such a fricking noob) :)

EDIT: Thanks very much for the answers - even though I could only pick one as the best answe they were all very helpful. And thanks for the comments as well - as some of them pointed out, What does the "yield" keyword do in Python? is a very good general guide to yield, generators and iterations even if I didn't find it an answer to my specific situation :)

12
  • Is this Python 2 or Python 3? Commented Mar 26, 2012 at 10:36
  • Hi George, your question has been answered here quite well I feel: stackoverflow.com/questions/231767/…
    – MattH
    Commented Mar 26, 2012 at 10:37
  • See this answer: stackoverflow.com/questions/231767/… Commented Mar 26, 2012 at 10:37
  • Python 2.7 Sorry, should have made that clear in the question. Commented Mar 26, 2012 at 10:37
  • 2
    Short answer you your question: You're mis-parsing the statement. yield yields the expression (padding_zeros + number_string).encode("ascii"), which is an ascii string as you have guessed. It probably helps to know that yield, like print in python 2, doesn't need parens around its argument.
    – alexis
    Commented Mar 26, 2012 at 10:49

4 Answers 4

7

OK, you know about generators, so the yield part needs no explanation. Fine.

So what does that line actually do? Not very much:

It concatenates padding_zeros and number_string and then encodes the result to ASCII. Which in Python 2.7 is a no-op because the string is ASCII to begin with (it only consists of ASCII digits, by definition).

In Python 3, it would be different; here the .encode() would have converted the string to a bytes object. But in Python 2, it doesn't make any sense.

1
  • Thanks - it might be that this code was originally written in Python 3 which would explain why it appears as a no op in Python 2. Can't be 100% certain though. Thanks for your answer and sorry for being so clueless. Commented Mar 26, 2012 at 11:10
4

yield is like return in a generator.

At the point that the yield is executed, execution of the generator function stops, and the value is returned. The difference is that when the generator is invoked again, execution restarts at the yield statement, and continues until another yield is hit, or an (unhandled) exception is raised, or a return is hit. The return or exception will terminate the generator.

The point of a generator is that one can invoke it as x = next(generator) or x = generator.next(), and each time one will receive the value from the yield inside the generator. Generators are also iterable, so they may be used as the source of a loop: for x in generator: print x.

Like in C#, the . operator invokes the method named on its right on the object appearing on the operator's left. Accordingly, (padding_zeros + number_string).encode("ascii") calls encode on the result of (padding_zeros + number_string).

For the meaning of encode, see here: http://docs.python.org/library/stdtypes.html#str.encode

For the language reference (assuming you are using python 2): http://docs.python.org/reference/index.html

0
1

In this case yield is used to perform lazy evaluation. The next codes are roughly equivalent:

def f(...):
    for current_length in range(4, max_length + 1):
        for i in range(0, pow(10, current_length)):
            number_string = str(i)
            padding_zeros = "0" * (current_length - len(number_string))
            yield (padding_zeros + number_string).encode("ascii")

result = list(f())

versus

def f(...):
    result = list()
    for current_length in range(4, max_length + 1):
        for i in range(0, pow(10, current_length)):
            number_string = str(i)
            padding_zeros = "0" * (current_length - len(number_string))
            result.append((padding_zeros + number_string).encode("ascii"))
    return result

result = f()

You may just follow the second one in you code translation.

3
  • 1
    Except that the second version returns a list, while the generator will yield each element one-by-one.
    – Marcin
    Commented Mar 26, 2012 at 10:43
  • @Marcin sure. But I don't think that OP cares about that :) Commented Mar 26, 2012 at 10:52
  • Well it's nice to understand the differences between the two but this should be particularly helpful when I get round to the conversion (still working on pseudocode for the rest of it). Commented Mar 26, 2012 at 10:58
0

a generator is a statemachine which implements the iterator interface or __iter__ in python. it will wait after "yield" until you call next() on it.

try this:

def my_gen():
    for current_length in range(4, max_length + 1):
        for i in range(0, pow(10, current_length)):
            number_string = str(i)
            padding_zeros = "0" * (current_length - len(number_string))
            print "generate %s" % i
            yield (padding_zeros + number_string).encode("ascii")

for i in my_gen():
    print "iterate %s" % i
4
  • A generator is not a statemachine -1: en.wikipedia.org/wiki/Finite-state_machine. In addition, the primary generator interface is next.
    – Marcin
    Commented Mar 26, 2012 at 10:49
  • i think it is (a quite simple one): every call to next() change its state, which allows it to move forward or to stop. (i edited the second 'iter' to 'next()')
    – mo.
    Commented Mar 26, 2012 at 11:22
  • That is not the definition of a statemachine.
    – Marcin
    Commented Mar 26, 2012 at 11:24
  • my understanding of this may come from .net.where yield generates a statemachine at compile time.i thougt it was similar in python
    – mo.
    Commented Mar 26, 2012 at 11:45

Not the answer you're looking for? Browse other questions tagged or ask your own question.