0

This is essentially 2 questions I think.

  1. How do I make all internal functions use the same raw_input?
  2. How do I chain functions with that input?

I've been trying to make something that will make a circle shape with whatever character the user inputs. (This is a "for fun" activity that I thought up to help me get used to functions. I've only been self teaching Python for 2 weeks now)
So far my code is:

def circle(symbol):

    def lines1(aa):
        print(symbol * 20)
        aa()
        print(symbol * 20)
    return(lines1)

    def lines2(bb):
        print(symbol * 7 + ' ' * 6 + symbol * 7)
        bb()
        print(symbol * 7 + ' ' * 6 + symbol * 7)
    return(lines2)

    def lines3(cc):
        print(symbol * 4 + ' ' * 12 + symbol * 4)
        cc()
        print(symbol * 4 + ' ' * 12 + symbol * 4)
    return(lines3)

    def lines4(dd):
        print(symbol * 2 + ' ' * 16 + symbol * 2)
        dd()
        print(symbol * 2 + ' ' * 16 + symbol * 2)
    return(lines4)

    def lines5():
        print(symbol + ' ' * 18 + symbol)
        print(symbol + ' ' * 18 + symbol)
    return(lines5)

    lines1(lines2(lines3(lines4(lines5()))))

circle(raw_input())

Example: If the user inputs a #, it is supposed to output:

####################
#######      #######
####            ####
##                ##
#                  #
#                  #
##                ##
####            ####
#######      #######
####################

The problem is it doesn't output anything.

Joseph Webber
  • 2,010
  • 1
  • 19
  • 38

3 Answers3

3

Your cicles function returns early:

def circle(symbol):

    def lines1(aa):
        print(symbol * 20)
        aa()
        print(symbol * 20)
    return(lines1)

The rest of your function is not executed.

Next, you use functions that want to call other functions, but you never pass in the arguments. aa() is not given any reference to the lines2() function.

Instead, you call lines5(), which returns None, then pass that to lines4(), which cannot call lines4().

You'll need inner wrappers to make this work the way you want to:

def circle(symbol):

    def lines1(inner):
        def wrapper():
            print(symbol * 20)
            inner()
            print(symbol * 20)
        return wrapper

    def lines2(inner):
        def wrapper():
            print(symbol * 7 + ' ' * 6 + symbol * 7)
            inner()
            print(symbol * 7 + ' ' * 6 + symbol * 7)
        return wrapper

    def lines3(inner):
        def wrapper():
            print(symbol * 4 + ' ' * 12 + symbol * 4)
            inner()
            print(symbol * 4 + ' ' * 12 + symbol * 4)
        return wrapper

    def lines4(inner):
        def wrapper():
            print(symbol * 2 + ' ' * 16 + symbol * 2)
            inner()
            print(symbol * 2 + ' ' * 16 + symbol * 2)
        return wrapper

    def lines5():
        print(symbol + ' ' * 18 + symbol)
        print(symbol + ' ' * 18 + symbol)

    lines1(lines2(lines3(lines4(lines5))))()

Now functions lines1 through lines4 each return a wrapper function to be passed into the next function, effectively making them decorators. We start with lines5 (as a function reference, not by calling it then call the result of the nested wrappers.

The definition of lines5 could now also use @decorator syntax:

    @lines1
    @lines2
    @lines3
    @lines4
    def lines5():
        print(symbol + ' ' * 18 + symbol)
        print(symbol + ' ' * 18 + symbol)

    line5()
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • I thought lines1(lines2(lines3(lines4(lines5())))) was passing in the next decorator as its argument, thus creating a chain down to lines5? – Joseph Webber May 10 '13 at 14:42
  • @JosephWebber: The **inner-most** function is executed first, so `lines5()` is executed, then it's return value is passed to `lines4()`, which is executed, etc. – Martijn Pieters May 10 '13 at 14:59
  • @JosephWebber: In my version, `lines5` is **not** executed. `lines4()` then executes, this time with `lines5` as an argument. It returns `wrapper`, another function. This is passed to `lines3()`, etc., until `lines1()` returns a wrapper function. **Then** we call that last return value. – Martijn Pieters May 10 '13 at 15:00
  • @JosephWebber: The `wrapper` from `lines1` then executes, prints a line and calls the `wrapper` returned by `lines2`; it prints a line, calls he `wrapper` from `lines3`, etc. all the way until `lines5` is called and returns. Then the other `print` lines are executed in reverse order. – Martijn Pieters May 10 '13 at 15:01
  • Thanks a bunch, but I just have one more question. Where is it appropriate/not appropriate to call a decorator? – Joseph Webber May 10 '13 at 15:14
  • @JosephWebber: anything that can be used with the `@decorator` syntax . Function decorators must return a callable, class decorators a class. That's about it. – Martijn Pieters May 10 '13 at 15:18
2

Your not using decorators,

To make your code work as is:

class circle(object):

    def __init__(self, symbol):    
        self.symbol = symbol

    def lines1(self):
        print(self.symbol * 20)
        print(self.symbol * 20)

    def lines2(self):
        print(self.symbol * 7 + ' ' * 6 + self.symbol * 7)
        print(self.symbol * 7 + ' ' * 6 + self.symbol * 7)


    def lines3(self):
        print(self.symbol * 4 + ' ' * 12 + self.symbol * 4)
        print(self.symbol * 4 + ' ' * 12 + self.symbol * 4)

    def lines4(self):
        print(self.symbol * 2 + ' ' * 16 + self.symbol * 2)
        print(self.symbol * 2 + ' ' * 16 + self.symbol * 2)

    def lines5(self):
        print(self.symbol + ' ' * 18 + self.symbol)
        print(self.symbol + ' ' * 18 + self.symbol)

    def print_circle(self):
        self.lines1()
        self.lines2()
        self.lines3()
        self.lines4()
        self.lines5()
        self.lines4()
        self.lines3()
        self.lines2()
        self.lines1()

x = circle(raw_input())
x.print_circle()

Check out this question on decorators I found it too be very helpful in the past: How to make a chain of function decorators?

Community
  • 1
  • 1
Noelkd
  • 7,686
  • 2
  • 29
  • 43
0

So much duplication there, and here is my functional style solution:

def cycle(s):
    def lines1(symbol):
        print(symbol * 20)

    def lines2(symbol):
        print(symbol * 7 + ' ' * 6 + symbol * 7)

    def lines3(symbol):
        print(symbol * 4 + ' ' * 12 + symbol * 4)

    def lines4(symbol):
        print(symbol * 2 + ' ' * 16 + symbol * 2)

    def lines5(symbol):
        print(symbol + ' ' * 18 + symbol)

    def combine(F, *FS):
        if not FS: return F
        fn, rest = FS[0], FS[1:]
        def wrapper(s):
            fn(s)
            F(s)
            fn(s)
        return combine(wrapper, *rest)

    return combine(lines5, lines4, lines3, lines2, lines1)(s)

cycle(raw_input())
Simon Shi
  • 106
  • 1
  • 6