user1569317
user1569317

Reputation: 2496

Function iterates with print but not with return

Python newbie here, running 2.7.

I am trying to create a program that uses a function to generate text, and then outputs the function-generated text to a file.

When just printing the function in powershell (like this: http://codepad.org/KftHaO6x), it iterates, as I want it to:

def writecode (q, a, b, c):
    while b < q:
        b = b + 1
        print "v%d_%d_%d = pairwise (caps[%d],sals[%d],poss[%d],poss[%d],poss[%d],pos_range)" %(a,b,c,a,a,a,b,c)
        print "votes%d_%d.append(v%d_%d_%d)" % (b,c,a,b,c,)
        print "v%d_%d_%d = pairwise (caps[%d],sals[%d],poss[%d],poss[%d],poss[%d],pos_range)" %(a,c,b,a,a,a,c,b)
        print "votes%d_%d.append(v%d_%d_%d)" % (c,b,a,c,b)

writecode (5,1,0,4)

When trying to output the function into a file (like this: http://codepad.org/8GJpp9QY), it only gives 1 value, i.e. does not iterate:

def writecode (q, a, b, c):
    while b < q:
        b = b + 1
        data_to_write = "v%d_%d_%d = pairwise (caps[%d],sals[%d],poss[%d],poss[%d],poss[%d],pos_range)" %(a,b,c,a,a,a,b,c)
        data_to_write_two = "votes%d_%d.append(v%d_%d_%d)" % (b,c,a,b,c,)
        data_to_write_three = "v%d_%d_%d = pairwise (caps[%d],sals[%d],poss[%d],poss[%d],poss[%d],pos_range)" %(a,c,b,a,a,a,c,b)
        data_to_write_four = "votes%d_%d.append(v%d_%d_%d)" % (c,b,a,c,b)
        return data_to_write
        return data_to_write_two
        return data_to_write_three
        return data_to_write_four

x = writecode (5,1,0,4)

out_file = open("code.txt", "a")
out_file.write(x)
out_file.close()

Why is this, and how can I make the output function iterate (like it does with print)?

Upvotes: 5

Views: 1369

Answers (4)

martineau
martineau

Reputation: 123463

In the version you're using to write the file, the function returns (via the first return statement) after the first iteration of the while loop. Based on what you have you might want something like this:

def writecode (q, a, b, c):
    results = []
    while b < q:
        b = b + 1
        results.append("v%d_%d_%d = pairwise (caps[%d],sals[%d],poss[%d],poss[%d],poss[%d],pos_range)" % (a,b,c,a,a,a,b,c))
        results.append("votes%d_%d.append(v%d_%d_%d)" % (b,c,a,b,c,))
        results.append("v%d_%d_%d = pairwise (caps[%d],sals[%d],poss[%d],poss[%d],poss[%d],pos_range)" % (a,c,b,a,a,a,c,b))
        results.append("votes%d_%d.append(v%d_%d_%d)" % (c,b,a,c,b))
        results.append("")
    return "\n".join(results)

x = writecode (5,1,0,4)

out_file = open("code.txt", "a")
out_file.write(x)
out_file.close()

Which works by accumulating each line of output into a list and then returns the single string with all the results joined together with newlines and a trailing newline.

Upvotes: 2

Hugh Bothwell
Hugh Bothwell

Reputation: 56644

A slight variation; I have used new-style string formatting with named fields, which should be easier to read.

Do be aware that you are generating some duplicated blocks (every case in which b==c appears twice in your output).

from textwrap import dedent

codeblock = dedent("""\
    v{a}_{b}_{c} = pairwise (caps[{a}],sals[{a}],poss[{a}],poss[{b}],poss[{c}],pos_range)
    votes{b}_{c}.append(v{a}_{b}_{c})
    v{a}_{c}_{b} = pairwise (caps[{a}],sals[{a}],poss[{a}],poss[{c}],poss[{b}],pos_range)
    votes{c}_{b}.append(v{a}_{c}_{b})
""")

def get_code (q, a, b, c):
    return ''.join(codeblock.format(a=a, b=b, c=c) for b in xrange(b, q))

def main():
    with open('code.txt', 'a') as outf:
        outf.write(get_code(5,1,0,4))

if __name__=="__main__":
    main()

Upvotes: 0

Sean Vieira
Sean Vieira

Reputation: 159905

Your issue is that you can only return once from a function:

def test():
    return 1
    return 2

x = test()
# x is now 1

You'll want to either use yield or return a tuple of values:

def this_will_work():
    yield 1
    yield 2

x = list(this_will_work()) # See below for why we are using list
# x is now [1, 2]

def so_will_this:
    return 1, 2

x = so_will_this()
# x is now (1, 2)

Using yield turns your function into a generator that can be iterated over - if you are only interested in all the final values you can use list to turn the generator into a list of all the values your generator yields. Alternately you can loop over it using for ... in.

Upvotes: 5

Hamish
Hamish

Reputation: 23316

return immediately exists the function:

return leaves the current function call with the expression list (or None) as return value.

You need to build the string as you go (or, for better performance, create a list of values and join at the end).

Upvotes: 1

Related Questions