Name bindings for inner functions.

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • trevor_morgan@yahoo.com

    #1

    Name bindings for inner functions.

    The following code:

    def functions():
    l=list()
    for i in range(5):
    def inner():
    return i
    l.append(inner)
    return l


    print [f() for f in functions()]


    returns [4,4,4,4,4], rather than the hoped for [0,1,2,3,4]. I presume
    this is something to do with the variable i getting re-bound every time
    we go through the loop, or something, but I'm not sure how to fix this.
    I've found the ability in python to create functions on the fly and
    store and index them for later use incredibly powerful, so it'd be nice
    to get past this little roadblock.

  • Andrea Griffini

    #2
    Re: Name bindings for inner functions.

    trevor_morgan@y ahoo.com wrote:
    The following code:
    >
    def functions():
    l=list()
    for i in range(5):
    def inner():
    return i
    l.append(inner)
    return l
    >
    >
    print [f() for f in functions()]
    >
    >
    returns [4,4,4,4,4], rather than the hoped for [0,1,2,3,4]. I presume
    this is something to do with the variable i getting re-bound every time
    we go through the loop, or something, but I'm not sure how to fix this.
    The problem is that "i" inside the function is indeed
    the same variable for all the functions (the one you're
    using for looping).

    If you want a different variable for each function
    you can use the somewhat ugly but idiomatic

    def functions():
    l=list()
    for i in range(5):
    def inner(i=i):
    return i
    l.append(inner)
    return l

    this way every function will have its own "i" variable,
    that is initialized with the value of the loop variable
    when executing the "def" statement.

    Andrea

    Comment

    • trevor_morgan@yahoo.com

      #3
      Re: Name bindings for inner functions.

      Thanks, that's exactly what I needed.
      Andrea Griffini wrote:
      trevor_morgan@y ahoo.com wrote:
      The following code:

      def functions():
      l=list()
      for i in range(5):
      def inner():
      return i
      l.append(inner)
      return l


      print [f() for f in functions()]


      returns [4,4,4,4,4], rather than the hoped for [0,1,2,3,4]. I presume
      this is something to do with the variable i getting re-bound every time
      we go through the loop, or something, but I'm not sure how to fix this.
      >
      The problem is that "i" inside the function is indeed
      the same variable for all the functions (the one you're
      using for looping).
      >
      If you want a different variable for each function
      you can use the somewhat ugly but idiomatic
      >
      def functions():
      l=list()
      for i in range(5):
      def inner(i=i):
      return i
      l.append(inner)
      return l
      >
      this way every function will have its own "i" variable,
      that is initialized with the value of the loop variable
      when executing the "def" statement.
      >
      Andrea

      Comment

      • Fredrik Lundh

        #4
        Re: Name bindings for inner functions.

        trevor_morgan@y ahoo.com wrote:
        The following code:
        >
        def functions():
        l=list()
        for i in range(5):
        def inner():
        return i
        l.append(inner)
        return l
        >
        >
        print [f() for f in functions()]
        >
        >
        returns [4,4,4,4,4], rather than the hoped for [0,1,2,3,4]. I presume
        this is something to do with the variable i getting re-bound every time
        we go through the loop
        free variables bind to *names*, not objects. all your functions will
        refer to the name "i" in "function"' s scope, which is bound to a 4 when
        the loop has finished.

        you can use the default argument mechanism to explicitly bind to an
        object instead of a name:

        def functions():
        l=list()
        for i in range(5):
        def inner(i=i):
        return i
        l.append(inner)
        return l

        </F>

        Comment

        • James Stroud

          #5
          Re: Name bindings for inner functions.

          Andrea Griffini wrote:
          trevor_morgan@y ahoo.com wrote:
          >
          >The following code:
          >>
          >def functions():
          > l=list()
          > for i in range(5):
          > def inner():
          > return i
          > l.append(inner)
          > return l
          >>
          >>
          >print [f() for f in functions()]
          >>
          >>
          >returns [4,4,4,4,4], rather than the hoped for [0,1,2,3,4]. I presume
          >this is something to do with the variable i getting re-bound every time
          >we go through the loop, or something, but I'm not sure how to fix this.
          >
          >
          The problem is that "i" inside the function is indeed
          the same variable for all the functions (the one you're
          using for looping).
          >
          If you want a different variable for each function
          you can use the somewhat ugly but idiomatic
          >
          def functions():
          l=list()
          for i in range(5):
          def inner(i=i):
          return i
          l.append(inner)
          return l
          >
          this way every function will have its own "i" variable,
          that is initialized with the value of the loop variable
          when executing the "def" statement.
          >
          Andrea
          Yet another way to skin the same cat, maybe even less ugly, depending on taste.

          def make_inner(i):
          def inner():
          return i
          return inner

          def functions():
          return [make_inner(i) for i in range(5)]

          print [f() for f in functions()]

          James

          --
          James Stroud
          UCLA-DOE Institute for Genomics and Proteomics
          Box 951570
          Los Angeles, CA 90095


          Comment

          Working...