3

So I'm wondering if this is possible. So, what I need to happen is to make my function return a string. Now the tricky part is that my function prints out a fancy pattern and I'm not sure how I can return my pattern as a string? I don't want it to actually print anything before I use the function in something like:

my_function(c,r)  
x = 4
y = 5  
a = my_function(x,y)
print(a)

Output:

*nothing here blank space*
*pattern printed*

Here is my code for the function my_function:

def my_function(c, r):  
    if(c > 0 and r > 0):

        print("*" * c)

        for i in range(r - 2):
            if(c == 1):
                print("*")
            elif(c > 1):
                print("*" + " " * (c - 2) + "*")

        if(r > 1):
            print("*" * c)

If I call the function as is, it will print everything. But I don't want it to print. I tried replacing all the print by return but it prints only the first line(which was not unexpected, since return will just terminate the function at line 1).

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Sab ಠ_ಠ
  • 135
  • 1
  • 4
  • 13
  • Separating input/output from program logic is *the* fundamental step to write good programs in any language. As a rule of thumb if a function contains a `print` then it should **not** compute anything that is useful elsewhere. – Bakuriu Apr 03 '14 at 14:06
  • @Bakuriu Could you please be more explicit in the explanation? I'm relatively new to programming in general. – Sab ಠ_ಠ Apr 03 '14 at 14:12
  • The problem with your function is that mixes interaction with the user with internal logic of the program. Check out the solutions that you received. You can clearly see that the functions described do *not* interact with the user at all. That's what I meant. Either a piece of code handle interaction with the user or it computes something, but it shouldn't do both. Describing this further would take too much time and space for a comment. – Bakuriu Apr 03 '14 at 14:16
  • @Bakuriu So, basically what you mean is that I should refrain from using print in a function? – Sab ಠ_ಠ Apr 03 '14 at 14:20
  • 1
    No. What I'm saying is that if a function contains a `print`, then it should contain *only* code that is related to the output or input. – Bakuriu Apr 03 '14 at 14:27

4 Answers4

4

Gather the values to return into one list, build a string at the end of your function to return:

def my_function(c, r):  
    lines = []
    if c and r:
        lines.append("*" * c)

        for i in range(r - 2):
            if c == 1:
                lines.append("*")
            else:
                lines.append("*" + " " * (c - 2) + "*")

        if r > 1:
            lines.append("*" * c)

    return '\n'.join(lines)

This includes the same newlines the print() function would write between each line.

Demo:

>>> print(my_function(4, 5))
****
*  *
*  *
*  *
****
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Is there another way other than lines.append? – Sab ಠ_ಠ Apr 03 '14 at 14:09
  • @Sab: You can make `lines` a string, then use `lines += "*" * c + '\n'`, but then you manually need to add the newlines, and it is not nearly as efficient (you are re-creating strings each time you concatenate). `str.join()` *once* is more efficient. – Martijn Pieters Apr 03 '14 at 14:10
  • The thing is I've not yet learned about arrays, so I was wondering if it was possible using something else. – Sab ಠ_ಠ Apr 03 '14 at 14:13
1

Meaningful names are also very helpful!

Edit: also: catching unexpected cases (like width < 2 * border) and code reuse (delegate repeated code to a sub-function).

def _box_section(width, border, outside, inside):
    if width <= 2 * border:
        # inside is occluded
        return outside * width
    else:
        return (
            outside * border
          + inside * (width - 2 * border)
          + outside * border
        )

def make_box(width, height, border=1, outside="*", inside=" "):
    top_row  = outside * width
    mid_row  = _box_section(width,  border, outside,   inside)
    box_rows = _box_section(height, border, [top_row], [mid_row])
    return "\n".join(box_rows)

print(make_box(4, 3, outside="#"))
print("")
print(make_box(8, 6, border=2, inside="."))

gives

####
#  #
####

********
********
**....**
**....**
********
********
Hugh Bothwell
  • 55,315
  • 8
  • 84
  • 99
0

Here is an unrelated example of how you can accomplish that:

def foo(bar):
    barz = bar
    a = 2
    c = 'c'
    d = 5.0
    return (barz,a,c,d)

>>> result = foo(5)
>>> print result[0]
5
>>> print result[2]
c
>>> print result
[5,2,'c',5.0]
sshashank124
  • 31,495
  • 9
  • 67
  • 76
0

You could gather all of your strings to a list and then print the contents of that list. But I feel this is a good exercise for writing a generator function:

def get_rectangle(c, r):  
    if(c > 0 and r > 0):

        yield "*" * c

        for i in range(r - 2):
            if(c == 1):
                yield "*"
            elif(c > 1):
                yield "*" + " " * (c - 2) + "*"

        if(r > 1):
            yield "*" * c

for c in get_rectangle(c, r):
    print c

DEMO:

In [5]: for i in get_rectangle(4, 5):
   ...:     print i
   ...:     
****
*  *
*  *
*  *
****

Another, more concise way to print the box using the generator..

In [9]: print("\n".join(get_rectangle(4, 5)))
****
*  *
*  *
*  *
****
msvalkon
  • 11,887
  • 2
  • 42
  • 38