setting variables in outer functions

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

    setting variables in outer functions

    Given the following:
    def outer(arg)
    avar = ''
    def inner1(arg2)
    # How can I set 'avar' here ?

    -------------------------------------
    This sig is dedicated to the advancement of Nuclear Power
    Tommy Nordgren
    tommy.nordgren@ comhem.se



  • brad

    #2
    Re: setting variables in outer functions

    Tommy Nordgren wrote:
    Given the following:
    def outer(arg)
    avar = ''
    def inner1(arg2)
    # How can I set 'avar' here ?
    Try this... works for me... maybe not for you?

    def outer(avar=Fals e):
    print avar
    if avar == True:
    return

    def inner(avar=True ):
    print avar
    return avar

    outer(inner())

    outer()

    Comment

    • Hrvoje Niksic

      #3
      Re: setting variables in outer functions

      Tommy Nordgren <tommy.nordgren @comhem.sewrite s:
      Given the following:
      def outer(arg)
      avar = ''
      def inner1(arg2)
      # How can I set 'avar' here ?
      I don't think you can, until Python 3:
      In most languages that support nested scopes, code can refer to or rebind (assign to) any name in the nearest enclosing scope. Currently, Python code can refer to a name in any enclosing scope, but it can only rebind names in two scopes: the local scope...


      Currently the (ugly) solution is to change variable assignment to
      object mutation:

      def outer(arg)
      avar = ['']
      # use avar[0] where you'd normally use avar
      def inner1(arg2)
      # modify the value of avar by setting avar[0]

      Comment

      • Tommy Nordgren

        #4
        Re: setting variables in outer functions


        On 29 okt 2007, at 21.59, brad wrote:
        Tommy Nordgren wrote:
        >Given the following:
        >def outer(arg)
        > avar = ''
        > def inner1(arg2)
        > # How can I set 'avar' here ?
        >
        Try this... works for me... maybe not for you?
        >
        def outer(avar=Fals e):
        print avar
        if avar == True:
        return
        >
        def inner(avar=True ):
        print avar
        return avar
        >
        outer(inner())
        >
        outer()
        --
        http://mail.python.org/mailman/listinfo/python-list
        This is not a general solution to this problem.
        What works, though, (I just thought of it) is to do the following:
        def outer(arg):
        adict = {}
        def inner1(arg):
        adict['avar'] = 'something'
        #now the value set by inner1 is available to other nested functions
        ------
        What is a woman that you forsake her, and the hearth fire and the
        home acre,
        to go with the old grey Widow Maker. --Kipling, harp song of the
        Dane women
        Tommy Nordgren
        tommy.nordgren@ comhem.se



        Comment

        • brad

          #5
          Re: setting variables in outer functions

          Tommy Nordgren wrote:
          >def outer(avar=Fals e):
          > print avar
          > if avar == True:
          > return
          >>
          > def inner(avar=True ):
          > print avar
          > return avar
          >>
          > outer(inner())
          >>
          >outer()
          This is not a general solution to this problem.
          Run my example code, it works (if I'm understanding your question
          correctly). It sets outer to True... inner returns True to outer and
          thus the var is set... am I missing something?

          Comment

          • Steven Bethard

            #6
            Re: setting variables in outer functions

            Hrvoje Niksic wrote:
            Tommy Nordgren <tommy.nordgren @comhem.sewrite s:
            >
            >Given the following:
            >def outer(arg)
            > avar = ''
            > def inner1(arg2)
            > # How can I set 'avar' here ?
            >
            I don't think you can, until Python 3:
            http://www.python.org/dev/peps/pep-3104/
            But it definitely does work in Python 3 if you use 'nonlocal'::

            Python 3.0a1+ (py3k:58681, Oct 26 2007, 19:44:30) [MSC v.1310 32 bit
            (Intel)] on win32
            Type "help", "copyright" , "credits" or "license" for more
            information.
            >>def f():
            ... x = 1
            ... def g():
            ... nonlocal x
            ... x = 2
            ... print(x)
            ... g()
            ... print(x)
            ...
            >>f()
            1
            2

            That said, I'd like to see the reason you think you want to do this.

            STeVe

            Comment

            • Neil Cerutti

              #7
              Re: setting variables in outer functions

              On 2007-10-29, Steven Bethard <steven.bethard @gmail.comwrote :
              Hrvoje Niksic wrote:
              >Tommy Nordgren <tommy.nordgren @comhem.sewrite s:
              >>
              >>Given the following:
              >>def outer(arg)
              >> avar = ''
              >> def inner1(arg2)
              >> # How can I set 'avar' here ?
              >>
              >I don't think you can, until Python 3:
              >http://www.python.org/dev/peps/pep-3104/
              >
              But it definitely does work in Python 3 if you use 'nonlocal'::
              >
              Python 3.0a1+ (py3k:58681, Oct 26 2007, 19:44:30) [MSC v.1310 32 bit
              (Intel)] on win32
              Type "help", "copyright" , "credits" or "license" for more
              information.
              >>def f():
              ... x = 1
              ... def g():
              ... nonlocal x
              ... x = 2
              ... print(x)
              ... g()
              ... print(x)
              ...
              >>f()
              1
              2
              >
              That said, I'd like to see the reason you think you want to do
              this.
              It's allows a standard programming idiom which provides a
              primitive form of object oriented programming using closures to
              represent state.

              def account(opening _balance):
              balance = opening_balance
              def get_balance():
              nonlocal balance
              return balance
              def post_transactio n(x):
              nonlocal balance
              balance += x
              return balance, post_transactio n

              fred_balance, fred_post = account(1500)
              joe_balance, joe_post = account(12)
              fred_post(20)
              joe_post(-10)
              fred_balance()
              1520
              joe_balance()
              2

              Python classes will of course nearly always win, though the idiom
              looks like it might be faster (I don't have Python 3000 to try it
              out).

              --
              Neil Cerutti
              It isn't pollution that is hurting the environment; it's the impurities in our
              air and water that are doing it. --Dan Quayle

              Comment

              • Steven Bethard

                #8
                Re: setting variables in outer functions

                Neil Cerutti wrote:
                On 2007-10-29, Steven Bethard <steven.bethard @gmail.comwrote :
                >Hrvoje Niksic wrote:
                >>Tommy Nordgren <tommy.nordgren @comhem.sewrite s:
                >>>
                >>>Given the following:
                >>>def outer(arg)
                >>> avar = ''
                >>> def inner1(arg2)
                >>> # How can I set 'avar' here ?
                >>I don't think you can, until Python 3:
                >>http://www.python.org/dev/peps/pep-3104/
                >But it definitely does work in Python 3 if you use 'nonlocal'::
                >>
                > Python 3.0a1+ (py3k:58681, Oct 26 2007, 19:44:30) [MSC v.1310 32 bit
                > (Intel)] on win32
                > Type "help", "copyright" , "credits" or "license" for more
                > information.
                > >>def f():
                > ... x = 1
                > ... def g():
                > ... nonlocal x
                > ... x = 2
                > ... print(x)
                > ... g()
                > ... print(x)
                > ...
                > >>f()
                > 1
                > 2
                >>
                >That said, I'd like to see the reason you think you want to do
                >this.
                >
                It's allows a standard programming idiom which provides a
                primitive form of object oriented programming using closures to
                represent state.
                Yeah, that's what I was afraid of. ;-)

                STeVe

                Comment

                • Duncan Booth

                  #9
                  Re: setting variables in outer functions

                  Neil Cerutti <horpner@yahoo. comwrote:
                  It's allows a standard programming idiom which provides a
                  primitive form of object oriented programming using closures to
                  represent state.
                  >
                  def account(opening _balance):
                  balance = opening_balance
                  def get_balance():
                  nonlocal balance
                  return balance
                  def post_transactio n(x):
                  nonlocal balance
                  balance += x
                  return balance, post_transactio n
                  >
                  fred_balance, fred_post = account(1500)
                  joe_balance, joe_post = account(12)
                  fred_post(20)
                  joe_post(-10)
                  fred_balance()
                  TypeError: 'int' object is not callable
                  1520
                  joe_balance()
                  TypeError: 'int' object is not callable
                  2
                  >
                  Python classes will of course nearly always win, though the idiom
                  looks like it might be faster (I don't have Python 3000 to try it
                  out).
                  Python classes might be less error prone. I expect they could also be
                  faster: accessing non-local variables (whether fetching or setting) has
                  always been suprisingly slow in Python 2.x.

                  Comment

                  • Bruno Desthuilliers

                    #10
                    Re: setting variables in outer functions

                    brad a écrit :
                    Tommy Nordgren wrote:
                    >
                    >>def outer(avar=Fals e):
                    >> print avar
                    >> if avar == True:
                    >> return
                    >>>
                    >> def inner(avar=True ):
                    >> print avar
                    >> return avar
                    >>>
                    >> outer(inner())
                    >>>
                    >>outer()
                    >
                    >
                    > This is not a general solution to this problem.
                    >
                    >
                    Run my example code, it works (if I'm understanding your question
                    correctly). It sets outer to True... inner returns True to outer and
                    thus the var is set... am I missing something?
                    Yes: you forgot to rebind avar in inner and check the result in outer.

                    Comment

                    • Dustan

                      #11
                      Re: setting variables in outer functions

                      On Oct 30, 11:29 am, Duncan Booth <duncan.bo...@i nvalid.invalid>
                      wrote:
                      Neil Cerutti <horp...@yahoo. comwrote:
                      It's allows a standard programming idiom which provides a
                      primitive form of object oriented programming using closures to
                      represent state.
                      >
                      def account(opening _balance):
                      balance = opening_balance
                      def get_balance():
                      nonlocal balance
                      return balance
                      def post_transactio n(x):
                      nonlocal balance
                      balance += x
                      return balance, post_transactio n
                      >
                      fred_balance, fred_post = account(1500)
                      joe_balance, joe_post = account(12)
                      fred_post(20)
                      joe_post(-10)
                      fred_balance()
                      >
                      TypeError: 'int' object is not callable
                      >
                      1520
                      joe_balance()
                      >
                      TypeError: 'int' object is not callable
                      >
                      2
                      >
                      Python classes will of course nearly always win, though the idiom
                      looks like it might be faster (I don't have Python 3000 to try it
                      out).
                      >
                      Python classes might be less error prone.
                      Why would using classes make your code any less prone to typographical
                      errors?

                      Comment

                      • Duncan Booth

                        #12
                        Re: setting variables in outer functions

                        Dustan <DustanGroups@g mail.comwrote:
                        On Oct 30, 11:29 am, Duncan Booth <duncan.bo...@i nvalid.invalid>
                        wrote:
                        >Neil Cerutti <horp...@yahoo. comwrote:
                        It's allows a standard programming idiom which provides a
                        primitive form of object oriented programming using closures to
                        represent state.
                        >>
                        def account(opening _balance):
                        balance = opening_balance
                        def get_balance():
                        nonlocal balance
                        return balance
                        def post_transactio n(x):
                        nonlocal balance
                        balance += x
                        return balance, post_transactio n
                        >>
                        fred_balance, fred_post = account(1500)
                        joe_balance, joe_post = account(12)
                        fred_post(20)
                        joe_post(-10)
                        fred_balance()
                        >>
                        >TypeError: 'int' object is not callable
                        >>
                        1520
                        joe_balance()
                        >>
                        >TypeError: 'int' object is not callable
                        >>
                        2
                        >>
                        Python classes will of course nearly always win, though the idiom
                        looks like it might be faster (I don't have Python 3000 to try it
                        out).
                        >>
                        >Python classes might be less error prone.
                        >
                        Why would using classes make your code any less prone to typographical
                        errors?
                        >
                        >
                        Lots of reasons: shorter and clearer code being high on the list. The
                        class equivalent would be:

                        >>class Account(object) :
                        def __init__(self, opening_balance ):
                        self.balance = opening_balance

                        def post_transactio n(self, x):
                        self.balance += x

                        >>fred = Account(1500)
                        >>joe = Account(12)
                        >>fred.post_tra nsaction(20)
                        >>joe.post_tran saction(-10)
                        >>fred.balanc e
                        1520
                        >>joe.balance
                        2

                        There is no scope for the particular error I highlighted: you no longer
                        have the duplication of declaring the functions and then returning them.
                        Also you don't need the accessor function at all (and if at some point
                        in the future you do want it you can make it a property).

                        You don't have to invent separate names for each of the returned
                        functions: the dot notation suddenly makes that a no brainer.

                        Also the class is easier to extend: you no longer have to find and
                        change every call to account() if you want to add another method: just
                        add it.

                        BTW, I put both the original code with corrections, and the class
                        version into a file and timed them running with Python 3 alpha 1, the
                        nested scope version is slightly faster: 5.03usec per loop against
                        5.77usec for the class version, but minor changes to the code can skew
                        the result either way (put in more attribute accesses and the class
                        wins, add in more method calls and the function wins).

                        Comment

                        • Dustan

                          #13
                          Re: setting variables in outer functions

                          On Oct 31, 7:08 am, Duncan Booth <duncan.bo...@i nvalid.invalidw rote:
                          Dustan <DustanGro...@g mail.comwrote:
                          On Oct 30, 11:29 am, Duncan Booth <duncan.bo...@i nvalid.invalid>
                          wrote:
                          Neil Cerutti <horp...@yahoo. comwrote:
                          It's allows a standard programming idiom which provides a
                          primitive form of object oriented programming using closures to
                          represent state.
                          >
                          def account(opening _balance):
                          balance = opening_balance
                          def get_balance():
                          nonlocal balance
                          return balance
                          def post_transactio n(x):
                          nonlocal balance
                          balance += x
                          return balance, post_transactio n
                          >
                          fred_balance, fred_post = account(1500)
                          joe_balance, joe_post = account(12)
                          fred_post(20)
                          joe_post(-10)
                          fred_balance()
                          >
                          TypeError: 'int' object is not callable
                          >
                          1520
                          joe_balance()
                          >
                          TypeError: 'int' object is not callable
                          >
                          2
                          >
                          Python classes will of course nearly always win, though the idiom
                          looks like it might be faster (I don't have Python 3000 to try it
                          out).
                          >
                          Python classes might be less error prone.
                          >
                          Why would using classes make your code any less prone to typographical
                          errors?
                          >
                          Lots of reasons: shorter and clearer code being high on the list.
                          It wouldn't be necessarily shorter, depending on what you're working
                          with. Clearer is a matter of opinion.
                          The
                          class equivalent would be:
                          >
                          >class Account(object) :
                          >
                          def __init__(self, opening_balance ):
                          self.balance = opening_balance
                          >
                          def post_transactio n(self, x):
                          self.balance += x
                          >
                          >fred = Account(1500)
                          >joe = Account(12)
                          >fred.post_tran saction(20)
                          >joe.post_trans action(-10)
                          >fred.balance
                          1520
                          >joe.balance
                          >
                          2
                          >
                          There is no scope for the particular error I highlighted: you no longer
                          have the duplication of declaring the functions and then returning them.
                          The 'particular error' you highlighted was a typographical error,
                          which can happen in any code. Sure, you can't have the exact same
                          typographical error, but that's what happens when you switch between
                          paradigms.
                          Also you don't need the accessor function at all (and if at some point
                          in the future you do want it you can make it a property).
                          >
                          You don't have to invent separate names for each of the returned
                          functions: the dot notation suddenly makes that a no brainer.
                          Fair enough; you got two valid arguments there.
                          Also the class is easier to extend: you no longer have to find and
                          change every call to account() if you want to add another method: just
                          add it.
                          Of course, there are cases where you'll never want to extend it.

                          Comment

                          • Chris Mellon

                            #14
                            Re: setting variables in outer functions

                            On Oct 31, 2007 5:49 PM, Dustan <DustanGroups@g mail.comwrote:
                            On Oct 31, 7:08 am, Duncan Booth <duncan.bo...@i nvalid.invalidw rote:
                            >
                            Dustan <DustanGro...@g mail.comwrote:
                            On Oct 30, 11:29 am, Duncan Booth <duncan.bo...@i nvalid.invalid>
                            wrote:
                            >Neil Cerutti <horp...@yahoo. comwrote:
                            It's allows a standard programming idiom which provides a
                            primitive form of object oriented programming using closures to
                            represent state.
                            def account(opening _balance):
                            balance = opening_balance
                            def get_balance():
                            nonlocal balance
                            return balance
                            def post_transactio n(x):
                            nonlocal balance
                            balance += x
                            return balance, post_transactio n
                            fred_balance, fred_post = account(1500)
                            joe_balance, joe_post = account(12)
                            fred_post(20)
                            joe_post(-10)
                            fred_balance()
                            >TypeError: 'int' object is not callable
                            1520
                            joe_balance()
                            >TypeError: 'int' object is not callable
                            2
                            Python classes will of course nearly always win, though the idiom
                            looks like it might be faster (I don't have Python 3000 to try it
                            out).
                            >Python classes might be less error prone.
                            Why would using classes make your code any less prone to typographical
                            errors?
                            Lots of reasons: shorter and clearer code being high on the list.
                            >
                            It wouldn't be necessarily shorter, depending on what you're working
                            with. Clearer is a matter of opinion.
                            >
                            It's going to be shorter in any non-trivial example, and even in most
                            trivial ones (as shown). Clearer may be a matter of opinion, but the
                            less complicated the code you're looking at is, the less chance you
                            have to make an error.
                            The
                            class equivalent would be:
                            >>class Account(object) :
                            def __init__(self, opening_balance ):
                            self.balance = opening_balance

                            def post_transactio n(self, x):
                            self.balance += x
                            >>fred = Account(1500)
                            >>joe = Account(12)
                            >>fred.post_tra nsaction(20)
                            >>joe.post_tran saction(-10)
                            >>fred.balanc e
                            1520
                            >>joe.balance
                            2

                            There is no scope for the particular error I highlighted: you no longer
                            have the duplication of declaring the functions and then returning them.
                            >
                            The 'particular error' you highlighted was a typographical error,
                            which can happen in any code. Sure, you can't have the exact same
                            typographical error, but that's what happens when you switch between
                            paradigms.
                            >
                            By having fewer explicit things to manage, you lessen the scope of
                            errors in naming those things. This is one reason why the DRY
                            principle is advocated - the fewer times you type something, the fewer
                            chances you have to typo it.
                            Also you don't need the accessor function at all (and if at some point
                            in the future you do want it you can make it a property).

                            You don't have to invent separate names for each of the returned
                            functions: the dot notation suddenly makes that a no brainer.
                            >
                            Fair enough; you got two valid arguments there.
                            >
                            Also the class is easier to extend: you no longer have to find and
                            change every call to account() if you want to add another method: just
                            add it.
                            >
                            Of course, there are cases where you'll never want to extend it.
                            >
                            Designing it in such a way that it's impossible to extend pretty much
                            ensures that, doesn't it?

                            I have no idea why someone who already has a working, object system
                            would want to implement their own on top of closures. I'd even take
                            issue with the idea that's it's a "standard" idiom for the quite
                            uncommon task of creating object systems, it's a well known conceptual
                            idea but it's not actually implemented as such very often.

                            Comment

                            • Hrvoje Niksic

                              #15
                              Re: setting variables in outer functions

                              "Chris Mellon" <arkanes@gmail. comwrites:
                              I have no idea why someone who already has a working, object system
                              would want to implement their own on top of closures.
                              This subthread is getting ridiculous -- closures are *not* useful only
                              for implementing object systems! The object system thing is just a
                              method of teaching abstractions popularized by SICP. Abstractions
                              normally taken for granted, such as objects, or even expression
                              evaluation, are implemented from scratch, using only the most basic
                              primitives available. In a Lisp-like language with lexical scope, the
                              most basic storage primitive is the lexical environment itself[1].

                              In real-life code, closures are used to implement callbacks with
                              automatic access to their lexical environment without the need for the
                              bogus additional "void *" argument one so often sees in C callbacks,
                              and without communication through global variables. If the callbacks
                              can access variables in the outer scope, it's only logical (and
                              useful) for them to be able to change them. Prohibiting modification
                              reduces the usefulness of closures and causes ugly workarounds such as
                              the avar[0] pattern.

                              If closures were useful only for implementing bogus object systems,
                              neither they nor "nonlocal" would have made it to Python in the first
                              place.


                              [1]
                              An illustration of that principle is an implementation of cons, the
                              most primitive Lisp storage type, without the use of a higher-level
                              storage object (such as a two-element vector):

                              (defun cons (x y)
                              (lambda (op)
                              (if op x y)))
                              (defun car (cons) (funcall cons t))
                              (defun cdr (cons) (funcall cons nil))

                              Comment

                              Working...