0

I am trying to make a function's output behave as if it's my input. The goal is to make a new output from the old output.

I have some code that looks like this:

def func():

    BLOCK OF CODE

func()

There is no return statement in the function and no parameters within the parenthesis. When I type func() to call my function as shown above, I get the desired output, which is a bunch of printed statements. Now I want to do something with that output to get another output. All I'm trying to do is effectively "pipe" the output of one function into the input of another function (or, if possible, not even worry about creating another function at all, and instead doing something more direct). I looked into Python 3 writing to a pipe but it did not help me. I also tried defining another function and using the preceding function as a parameter, which did not work either:

def another_func(func):
    print another_statement

another_func(func)

I also tried making a closure (which "kind" of worked because at least it printed the same thing that func() would print, but still not very encouraging):

def func():
    def another_func():
        print another_statement
    BLOCK OF CODE

another_func()

Finally, I tried designing both a decorator and a nested function to accomplish this, but I have no parameters in my function, which really threw off my code (didn't print anything at all).

Any advice on how to manipulate a function's output like as if it is your input so that it's possible to create a new output?

Community
  • 1
  • 1
warship
  • 2,924
  • 6
  • 39
  • 65
  • 5
    `print` is not "output of a function", but a side-effect upon a stream. The problem of intercepting `print` is made extra .. fun .. in Python 2.x where print is a special built-in. – user2864740 Aug 20 '14 at 00:01
  • see my answer ... it should work ... even though i think its probably ill advised to use in real code ... – Joran Beasley Aug 20 '14 at 00:10

4 Answers4

2

You could achieve this by redirecting stdout using a decorator:

from StringIO import StringIO
import sys

def pipe(f):
    def decorated(*args, **kwargs):
        old,sys.stdout = sys.stdout,StringIO()

        try:
            result = f(*args, **kwargs)
            output = sys.stdout.getvalue()
        finally:
            sys.stdout = old

        return result, output
    return decorated

You could then get the result, output pair from any decorated function, eg:

@pipe
def test(x):
    print x
    return 0

test(3) -> (0, '3\n')

However, I can't think of a good reason why you'd want to do this.

(Actually, that's not quite true; it is handy when writing unit tests for user IO, such as when testing student assignments in a software engineering course. I seriously doubt that that's what the OP is trying to do, though.)

sapi
  • 9,944
  • 8
  • 41
  • 71
  • +1 same as my answer... but prettier and with the very valid disclaimer of "I cant think of a good reason to do this" – Joran Beasley Aug 20 '14 at 00:12
  • @JoranBeasley - Prettier, but yours was more functional (as mine wasn't fixing stdout when an exception was raised). Stolen and fixed, thanks :) – sapi Aug 20 '14 at 00:14
1

Return the desired value(s) from the function - instead of printing the values on the console, return them as strings, numbers, lists or any other type that makes sense. Otherwise, how do you expect to "connect" the output of a function as the input to another, if there is no output to begin with?

Of course, printing on the console doesn't count as output unless you're planning to eventually use OS pipes or a similar mechanism to connect two programs on the console, but keep things simple! just use the function's return values and worry about pipes later if and only if that's necessary for your problem in particular.

After reading the comments: "connecting" two functions by printing on the console from one and reading from the console from the other would be a really bad idea in this case, first you have to grasp the way functions return values to each other, trust me on this one: you have to rethink your program! even though other answers (strictly speaking) answer your original question, that's absolutely not what you should do.

Óscar López
  • 232,561
  • 37
  • 312
  • 386
  • Because I had a big list of for loops, each following each other, that would sequentially print stuff to the screen. Then, once the output looked a certain way, I wanted to do one more thing to it but realized that just putting that command following all my for loops would not get the job done. Thus, I wrapped all my for loops into a function, then called the function with func(). No return statements were needed to print my output when I typed func() and so I suppose I should put a return statement at the end... I tried but it didn't help. – warship Aug 20 '14 at 00:07
  • Accumulate all the output in a list and return it at the end. Printing results is not the way to think about the solution to this problem! – Óscar López Aug 20 '14 at 00:09
  • I understand, but where would I put the `return` if I have a list of `for` loops as my code block, after every `for` loop I'd have a `print` statement originally... – warship Aug 20 '14 at 00:10
  • 1
    Instead of printing each value append it to a list, and return the list at the very end of the function – Óscar López Aug 20 '14 at 00:11
1

just for fun ... because OP asked for it

import StringIO
import sys
def func1():
    for i in range(1,10):
        print "some stuff %d"%i

def func2(func):
    old_std = sys.stdout
    sys.stdout = StringIO.StringIO()
    try:
        func()
        return sys.stdout.getvalue().splitlines()

    finally:
        sys.stdout = old_std


print func2(func1)
Joran Beasley
  • 110,522
  • 12
  • 160
  • 179
0

You need to return a value from your function. This can be used to assign the value into another variable.

Say I define some function doubleThis that will double the input

def doubleThis(x):
    print 'this is x :', x
    return x * 2    # note the return keyword

Now I can call the function with 3, and it returns 6 as expected

>>> doubleThis(3)
this is x : 3
6

Now I have another function subtractOne that returns the input value, minus 1.

def subtractOne(i):
    print 'this is i :', i
    return i - 1

Now comes the answer to your question. Note that we can call the first function as the input to the second, due to the fact that it has a return value.

>>> subtractOne(doubleThis(3))
this is x : 3
this is i : 6
5
Cory Kramer
  • 114,268
  • 16
  • 167
  • 218