function parameter scope python 2.5.2

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • J Kenneth King

    function parameter scope python 2.5.2


    I recently encountered some interesting behaviour that looks like a bug
    to me, but I can't find the appropriate reference to any specifications
    to clarify whether it is a bug.

    Here's the example code to demonstrate the issue:

    class SomeObject(obje ct):

    def __init__(self):
    self.words = ['one', 'two', 'three', 'four', 'five']

    def main(self):
    recursive_func( self.words)
    print self.words

    def recursive_func( words):
    if len(words) 0:
    word = words.pop()
    print "Popped: %s" % word
    recursive_func( words)
    else:
    print "Done"

    if __name__ == '__main__':
    weird_obj = SomeObject()
    weird_obj.main( )


    The output is:

    Popped: five
    Popped: four
    Popped: three
    Popped: two
    Popped: one
    Done
    []

    Of course I expected that recursive_func( ) would receive a copy of
    weird_obj.words but it appears to happily modify the object.

    Of course a work around is to explicitly create a copy of the object
    property befor passing it to recursive_func, but if it's used more than
    once inside various parts of the class that could get messy.

    Any thoughts? Am I crazy and this is supposed to be the way python works?
  • J Kenneth King

    #2
    Re: function parameter scope python 2.5.2

    J Kenneth King <james@agentult ra.comwrites:
    I recently encountered some interesting behaviour that looks like a bug
    to me, but I can't find the appropriate reference to any specifications
    to clarify whether it is a bug.
    >
    Here's the example code to demonstrate the issue:
    >
    class SomeObject(obje ct):
    >
    def __init__(self):
    self.words = ['one', 'two', 'three', 'four', 'five']
    >
    def main(self):
    recursive_func( self.words)
    print self.words
    >
    def recursive_func( words):
    if len(words) 0:
    word = words.pop()
    print "Popped: %s" % word
    recursive_func( words)
    else:
    print "Done"
    >
    if __name__ == '__main__':
    weird_obj = SomeObject()
    weird_obj.main( )
    >
    >
    The output is:
    >
    Popped: five
    Popped: four
    Popped: three
    Popped: two
    Popped: one
    Done
    []
    >
    Of course I expected that recursive_func( ) would receive a copy of
    weird_obj.words but it appears to happily modify the object.
    >
    Of course a work around is to explicitly create a copy of the object
    property befor passing it to recursive_func, but if it's used more than
    once inside various parts of the class that could get messy.
    >
    Any thoughts? Am I crazy and this is supposed to be the way python works?
    Of course, providing a shallow (or deep as necessary) copy makes it
    work, I'm curious as to why the value passed as a parameter to a
    function outside the class is passed a reference rather than a copy.

    Comment

    • alex23

      #3
      Re: function parameter scope python 2.5.2

      On Nov 21, 9:40 am, J Kenneth King <ja...@agentult ra.comwrote:
      Of course, providing a shallow (or deep as necessary) copy makes it
      work, I'm curious as to why the value passed as a parameter to a
      function outside the class is passed a reference rather than a copy.
      You're passing neither a reference nor a copy, you're passing the
      object (in this case a list) directly:


      Comment

      • George Sakkis

        #4
        Re: function parameter scope python 2.5.2

        On Nov 20, 6:40 pm, J Kenneth King <ja...@agentult ra.comwrote:
        J Kenneth King <ja...@agentult ra.comwrites:
        >
        >
        >
        I recently encountered some interesting behaviour that looks like a bug
        to me, but I can't find the appropriate reference to any specifications
        to clarify whether it is a bug.
        >
        Here's the example code to demonstrate the issue:
        >
        class SomeObject(obje ct):
        >
            def __init__(self):
                self.words = ['one', 'two', 'three', 'four', 'five']
        >
            def main(self):
                recursive_func( self.words)
                print self.words
        >
        def recursive_func( words):
            if len(words) 0:
                word = words.pop()
                print "Popped: %s" % word
                recursive_func( words)
            else:
                print "Done"
        >
        if __name__ == '__main__':
            weird_obj = SomeObject()
            weird_obj.main( )
        >
        The output is:
        >
        Popped: five
        Popped: four
        Popped: three
        Popped: two
        Popped: one
        Done
        []
        >
        Of course I expected that recursive_func( ) would receive a copy of
        weird_obj.words but it appears to happily modify the object.
        >
        Of course a work around is to explicitly create a copy of the object
        property befor passing it to recursive_func, but if it's used more than
        once inside various parts of the class that could get messy.
        >
        Any thoughts? Am I crazy and this is supposed to be the way python works?
        >
        Of course, providing a shallow (or deep as necessary) copy makes it
        work, I'm curious as to why the value passed as a parameter to a
        function outside the class is passed a reference rather than a copy.
        Why should it be a copy by default ? In Python all copies have to be
        explicit.

        George

        Comment

        • Rafe

          #5
          Re: function parameter scope python 2.5.2

          On Nov 21, 6:31 am, J Kenneth King <ja...@agentult ra.comwrote:
          I recently encountered some interesting behaviour that looks like a bug
          to me, but I can't find the appropriate reference to any specifications
          to clarify whether it is a bug.
          >
          Here's the example code to demonstrate the issue:
          >
          class SomeObject(obje ct):
          >
              def __init__(self):
                  self.words = ['one', 'two', 'three', 'four', 'five']
          >
              def main(self):
                  recursive_func( self.words)
                  print self.words
          >
          def recursive_func( words):
              if len(words) 0:
                  word = words.pop()
                  print "Popped: %s" % word
                  recursive_func( words)
              else:
                  print "Done"
          >
          if __name__ == '__main__':
              weird_obj = SomeObject()
              weird_obj.main( )
          >
          The output is:
          >
          Popped: five
          Popped: four
          Popped: three
          Popped: two
          Popped: one
          Done
          []
          >
          Of course I expected that recursive_func( ) would receive a copy of
          weird_obj.words but it appears to happily modify the object.
          >
          Of course a work around is to explicitly create a copy of the object
          property befor passing it to recursive_func, but if it's used more than
          once inside various parts of the class that could get messy.
          >
          Any thoughts? Am I crazy and this is supposed to be the way python works?
          You are passing a mutable object. So it can be changed. If you want a
          copy, use slice:
          >>L = [1, 2, 3, 4, 5]
          >>copy = L[:]
          >>L.pop()
          5
          >>L
          [1, 2, 3, 4]
          >>copy
          [1, 2, 3, 4, 5]

          ....in your code...

          def main(self):
          recursive_func( self.words[:])
          print self.words

          ....or...
          >>def recursive_func( words):
          >> words = words[:]
          >> if len(words) 0:
          >> word = words.pop()
          >> print "Popped: %s" % word
          >> recursive_func( words)
          >> else:
          >> print "Done"
          >>>
          >>words = ["one", "two", "three"]
          >>recursive_fun c(words)
          Popped: three
          Popped: two
          Popped: one
          Done
          >>words
          ['one', 'two', 'three']

          Though I haven't been doing this long enough to know if that last
          example has any drawbacks.

          If we knew more about what you are trying to do, perhaps an
          alternative would be even better.

          - Rafe

          Comment

          • Steven D'Aprano

            #6
            Re: function parameter scope python 2.5.2

            On Thu, 20 Nov 2008 18:31:12 -0500, J Kenneth King wrote:
            Of course I expected that recursive_func( ) would receive a copy of
            weird_obj.words but it appears to happily modify the object.
            I am curious why you thought that. What made you think Python should/did
            make a copy of weird_obj.words when you pass it to a function?

            This is a serious question, I'm not trying to trap you into something :)


            --
            Steven

            Comment

            • Arnaud Delobelle

              #7
              Re: function parameter scope python 2.5.2

              J Kenneth King <james@agentult ra.comwrites:
              I recently encountered some interesting behaviour that looks like a bug
              to me, but I can't find the appropriate reference to any specifications
              to clarify whether it is a bug.
              >
              Here's the example code to demonstrate the issue:
              >
              class SomeObject(obje ct):
              >
              def __init__(self):
              self.words = ['one', 'two', 'three', 'four', 'five']
              >
              def main(self):
              recursive_func( self.words)
              print self.words
              >
              def recursive_func( words):
              if len(words) 0:
              word = words.pop()
              print "Popped: %s" % word
              recursive_func( words)
              else:
              print "Done"
              >
              if __name__ == '__main__':
              weird_obj = SomeObject()
              weird_obj.main( )
              >
              >
              The output is:
              >
              Popped: five
              Popped: four
              Popped: three
              Popped: two
              Popped: one
              Done
              []
              >
              Of course I expected that recursive_func( ) would receive a copy of
              weird_obj.words but it appears to happily modify the object.
              >
              Of course a work around is to explicitly create a copy of the object
              property befor passing it to recursive_func, but if it's used more than
              once inside various parts of the class that could get messy.
              >
              Any thoughts? Am I crazy and this is supposed to be the way python works?
              That's because Python isn't call-by-value. Or it is according to some,
              it's just that the values it passes are references. Which, according to
              others, is unnecessarily convoluted: it's call-by-object, or shall we
              call it call-by-sharing? At least everybody agrees it's not
              call-by-reference or call-by-name.

              There. I hope this helps!

              --
              Arnaud

              Comment

              • J Kenneth King

                #8
                Re: function parameter scope python 2.5.2

                alex23 <wuwei23@gmail. comwrites:
                On Nov 21, 9:40 am, J Kenneth King <ja...@agentult ra.comwrote:
                >Of course, providing a shallow (or deep as necessary) copy makes it
                >work, I'm curious as to why the value passed as a parameter to a
                >function outside the class is passed a reference rather than a copy.
                >
                You're passing neither a reference nor a copy, you're passing the
                object (in this case a list) directly:
                >
                http://effbot.org/zone/call-by-object.htm
                Ah, thanks -- that's precisely what I was looking for.

                I knew it couldn't be a mistake; I just couldn't find the documentation
                on the behaviour since I didn't know what it was called in the python
                world.

                Cheers.

                Comment

                • J Kenneth King

                  #9
                  Re: function parameter scope python 2.5.2

                  Steven D'Aprano <steve@REMOVE-THIS-cybersource.com .auwrites:
                  On Thu, 20 Nov 2008 18:31:12 -0500, J Kenneth King wrote:
                  >
                  >Of course I expected that recursive_func( ) would receive a copy of
                  >weird_obj.word s but it appears to happily modify the object.
                  >
                  I am curious why you thought that. What made you think Python should/did
                  make a copy of weird_obj.words when you pass it to a function?
                  >
                  This is a serious question, I'm not trying to trap you into something :)
                  Don't worry, I don't feel "trapped" in usenet. ;)

                  It was more of an intuitive expectation than a suggestion that Python
                  got something wrong.

                  I was working on a program of some complexity recently and quickly
                  caught the issue in my tests. I knew what was going on and fixed it
                  expediently, but the behaviour confused me and I couldn't find any
                  technical documentation on it so I figured I just didn't know what it
                  was referred to in Python. Hence the post. :)

                  I suppose I have some functional sensibilities and assumed that an
                  object wouldn't let a non-member modify its properties even if they were
                  mutable.

                  Of course if there is any further reading on the subject, I'd appreciate
                  some links.

                  Cheers.

                  Comment

                  • Peter Pearson

                    #10
                    Re: function parameter scope python 2.5.2

                    On Fri, 21 Nov 2008 10:12:08 -0500, J Kenneth King wrote:
                    Steven D'Aprano <steve@REMOVE-THIS-cybersource.com .auwrites:
                    >>
                    >I am curious why you thought that. What made you think Python should/did
                    >make a copy of weird_obj.words when you pass it to a function?
                    [snip]
                    Of course if there is any further reading on the subject, I'd appreciate
                    some links.
                    As one relatively new Python fan to another, I recommend following
                    this newsgroup. Many important aspects of Python that several books
                    failed to drive through my skull are very clearly (and repeatedly)
                    explained here. Hang around for a week, paying attention to posts
                    with subjects like "Error in Python subscripts" (made-up example),
                    and curse me if you don't find it greatly rewarding.

                    --
                    To email me, substitute nowhere->spamcop, invalid->net.

                    Comment

                    • J Kenneth King

                      #11
                      Re: function parameter scope python 2.5.2

                      Peter Pearson <ppearson@nowhe re.invalidwrite s:
                      On Fri, 21 Nov 2008 10:12:08 -0500, J Kenneth King wrote:
                      >Steven D'Aprano <steve@REMOVE-THIS-cybersource.com .auwrites:
                      >>>
                      >>I am curious why you thought that. What made you think Python should/did
                      >>make a copy of weird_obj.words when you pass it to a function?
                      [snip]
                      >Of course if there is any further reading on the subject, I'd appreciate
                      >some links.
                      >
                      As one relatively new Python fan to another, I recommend following
                      this newsgroup. Many important aspects of Python that several books
                      failed to drive through my skull are very clearly (and repeatedly)
                      explained here. Hang around for a week, paying attention to posts
                      with subjects like "Error in Python subscripts" (made-up example),
                      and curse me if you don't find it greatly rewarding.
                      I do lurk more often than I post and sometimes I help out people new to
                      Python or new to programming in general. I know how helpful usenet can
                      be and usually this group in particular is quite special. It's good
                      advice to read before you post; quite often the question has been
                      proposed and answered long before it came to your little head (not you
                      in particular; just general "you").

                      In this case, I was simply lacking the terminology to find what I was
                      looking for on the subject. In such cases turning to the community seems
                      like a fairly reasonable way to find clarification. I've only been
                      programming in Python specifically for two years or so now, so I hope I
                      can be forgiven.

                      Cheers.

                      Comment

                      • Terry Reedy

                        #12
                        Re: function parameter scope python 2.5.2

                        J Kenneth King wrote:
                        I was working on a program of some complexity recently and quickly
                        caught the issue in my tests. I knew what was going on and fixed it
                        expediently, but the behaviour confused me and I couldn't find any
                        technical documentation on it so I figured I just didn't know what it
                        was referred to in Python. Hence the post. :)
                        Language Reference / Expressions / Primaries / Calls +
                        Language Reference / Compound statements / Function definitions

                        Hmm. Read by themselves, these are not as clear as they could be that
                        what parameters get bound to are the argument objects. One really needs
                        to have read the section on assignment statements first.

                        Comment

                        Working...