bad recursion, still works

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • iu2

    bad recursion, still works

    Hi,

    I wrote this wrong recursive function that flattens a list:

    def flatten(lst, acc=[]):
    #print 'acc =', acc, 'lst =', lst
    if type(lst) != list:
    acc.append(lst)
    else:
    for item in lst:
    flatten(item)
    return acc

    a = [1, 2, [3, 4, 5], [6, [7, 8, [9, 10], 11], 12], 13, 14]
    b = flatten(a)
    print b

    I was amazed to realize that it flattens the list alright. Why? 'acc'
    should be an empty list on each invocation of flatten, but is seems to
    accumulate anyway...

  • mdsherry@gmail.com

    #2
    Re: bad recursion, still works

    On Jul 15, 2:59 pm, iu2 <isra...@elbit. co.ilwrote:
    Hi,
    >
    I wrote this wrong recursive function that flattens a list:
    >
    def flatten(lst, acc=[]):
        #print 'acc =', acc, 'lst =', lst
        if type(lst) != list:
            acc.append(lst)
        else:
            for item in lst:
                flatten(item)
        return acc
    >
    a = [1, 2, [3, 4, 5], [6, [7, 8, [9, 10], 11], 12], 13, 14]
    b = flatten(a)
    print b
    >
    I was amazed to realize that it flattens the list alright. Why? 'acc'
    should be an empty list on each invocation of flatten, but is seems to
    accumulate anyway...
    When you say acc=[] in the function declaration, it binds acc to a
    particular list object, rather than to a concept of an empty list.
    Thus, all operations being performed on acc are being performed on the
    same list. If, after the sample code you provided, were to call

    c = flatten([15,16,17,[18,19]])
    print c

    you would get back the list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
    13, 14, 15, 16, 17, 18, 19].

    Mark Sherry

    Comment

    • iu2

      #3
      Re: bad recursion, still works

      On Jul 15, 9:30 pm, mdshe...@gmail. com wrote:
      On Jul 15, 2:59 pm, iu2 <isra...@elbit. co.ilwrote:
      >
      >
      >
      Hi,
      >
      I wrote this wrong recursive function that flattens a list:
      >
      def flatten(lst, acc=[]):
          #print 'acc =', acc, 'lst =', lst
          if type(lst) != list:
              acc.append(lst)
          else:
              for item in lst:
                  flatten(item)
          return acc
      >
      a = [1, 2, [3, 4, 5], [6, [7, 8, [9, 10], 11], 12], 13, 14]
      b = flatten(a)
      print b
      >
      I was amazed to realize that it flattens the list alright. Why? 'acc'
      should be an empty list on each invocation of flatten, but is seems to
      accumulate anyway...
      >
      When you say acc=[] in the function declaration, it binds acc to a
      particular list object, rather than to a concept of an empty list.
      Thus, all operations being performed on acc are being performed on the
      same list. If, after the sample code you provided, were to call
      >
      c = flatten([15,16,17,[18,19]])
      print c
      >
      you would get back the list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
      13, 14, 15, 16, 17, 18, 19].
      >
      Mark Sherry
      I still don't understand: In each recursive call to flatten, acc
      should be bound to a new [], shouldn't it? Why does the binding happen
      only on the first call to flatten?

      Comment

      • mdsherry@gmail.com

        #4
        Re: bad recursion, still works

        On Jul 15, 4:12 pm, iu2 <isra...@elbit. co.ilwrote:
        On Jul 15, 9:30 pm, mdshe...@gmail. com wrote:
        >
        >
        >
        On Jul 15, 2:59 pm, iu2 <isra...@elbit. co.ilwrote:
        >
        Hi,
        >
        I wrote this wrong recursive function that flattens a list:
        >
        def flatten(lst, acc=[]):
            #print 'acc =', acc, 'lst =', lst
            if type(lst) != list:
                acc.append(lst)
            else:
                for item in lst:
                    flatten(item)
            return acc
        >
        a = [1, 2, [3, 4, 5], [6, [7, 8, [9, 10], 11], 12], 13, 14]
        b = flatten(a)
        print b
        >
        I was amazed to realize that it flattens the list alright. Why? 'acc'
        should be an empty list on each invocation of flatten, but is seems to
        accumulate anyway...
        >
        When you say acc=[] in the function declaration, it binds acc to a
        particular list object, rather than to a concept of an empty list.
        Thus, all operations being performed on acc are being performed on the
        same list. If, after the sample code you provided, were to call
        >
        c = flatten([15,16,17,[18,19]])
        print c
        >
        you would get back the list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
        13, 14, 15, 16, 17, 18, 19].
        >
        Mark Sherry
        >
        I still don't understand: In each recursive call to flatten, acc
        should be bound to a new [], shouldn't it? Why does the binding happen
        only on the first call to flatten?
        Default values are bound when the function is defined, not when it's
        called. For example,
        >>import random
        >>def foo(bar = random.random() ):
        ... print bar
        ...
        >>foo()
        0.6323125498213 12
        >>foo()
        0.6323125498213 12

        If you view [...] just as shorthand for list(...), it might make a bit
        more sense. For immutable values, one can't change the value bound to
        the name, only what the name is bound to, so this behaviour is less
        obvious. But still there.

        As to why default values are evaluated at define time vs. call time,
        I'd argue reasons of scope and speed - if the default value is a
        computed constant, it makes little sense to recompute it every time
        the function is called.

        Mark Sherry

        Comment

        • Michael Torrie

          #5
          Re: bad recursion, still works

          iu2 wrote:
          I still don't understand: In each recursive call to flatten, acc
          should be bound to a new [], shouldn't it? Why does the binding happen
          only on the first call to flatten?
          Nope. In each new call it's (re)bound to the same original list, which
          you've added to as your function continues--it's mutable. Default
          variables that are bound to mutable objects are one of the big caveats
          that is mentioned in the FAQ.

          Comment

          • iu2

            #6
            Re: bad recursion, still works

            On Jul 16, 2:21 am, Michael Torrie <torr...@gmail. comwrote:
            iu2 wrote:
            I still don't understand: In each recursive call to flatten, acc
            should be bound to a new [], shouldn't it? Why does the binding happen
            only on the first call to flatten?
            >
            Nope.  In each new call it's (re)bound to the same original list, which
            you've added to as your function continues--it's mutable.  Default
            variables that are bound to mutable objects are one of the big caveats
            that is mentioned in the FAQ.
            Thanks guys, it's clear now

            Comment

            Working...