473,320 Members | 2,145 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

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(object):

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?
Nov 20 '08 #1
11 1947
J Kenneth King <ja***@agentultra.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(object):

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.
Nov 20 '08 #2
On Nov 21, 9:40*am, J Kenneth King <ja...@agentultra.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
Nov 20 '08 #3
On Nov 20, 6:40*pm, J Kenneth King <ja...@agentultra.comwrote:
J Kenneth King <ja...@agentultra.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(object):
* * 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
Nov 21 '08 #4
On Nov 21, 6:31*am, J Kenneth King <ja...@agentultra.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(object):

* * 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_func(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
Nov 21 '08 #5
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
Nov 21 '08 #6
J Kenneth King <ja***@agentultra.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(object):

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
Nov 21 '08 #7
alex23 <wu*****@gmail.comwrites:
On Nov 21, 9:40Â*am, J Kenneth King <ja...@agentultra.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.
Nov 21 '08 #8
Steven D'Aprano <st***@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.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 :)
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.
Nov 21 '08 #9
On Fri, 21 Nov 2008 10:12:08 -0500, J Kenneth King wrote:
Steven D'Aprano <st***@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.
Nov 21 '08 #10
Peter Pearson <pp******@nowhere.invalidwrites:
On Fri, 21 Nov 2008 10:12:08 -0500, J Kenneth King wrote:
>Steven D'Aprano <st***@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.
Nov 21 '08 #11
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.

Nov 21 '08 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: domeceo | last post by:
can anyone tell me why I cannot pass values in a setTimeout function whenever I use this function it says "menu is undefined" after th alert. function imgOff(menu, num) { if (document.images) {...
20
by: Gregory Piñero | last post by:
Hey guys, would someone mind giving me a quick rundown of how references work in Python when passing arguments into functions? The code below should highlight my specific confusion: <code> ...
2
by: FAN | last post by:
I want to define some function in python script dynamicly and call them later, but I get some problem. I have tried the following: ################################## # code...
38
by: Lasse Vågsæther Karlsen | last post by:
After working through a fair number of the challenges at www.mathschallenge.net, I noticed that some long-running functions can be helped *a lot* by caching their function results and retrieving...
5
by: Martin Johansen | last post by:
Hello C programmers If I have a function, say void f(int a, char b); And I call this function with the following arguments char a; int b;
16
by: Rob Somers | last post by:
Say I have the following code: void foo(int some_int); ..... int x = 5; foo(x); ..... void foo(int some_int) {
7
by: Csaba Gabor | last post by:
I feel like it's the twilight zone here as several seemingly trivial questions are bugging me. The first of the following three lines is a syntax error, while the last one is the only one that...
78
by: Josiah Manson | last post by:
I found that I was repeating the same couple of lines over and over in a function and decided to split those lines into a nested function after copying one too many minor changes all over. The only...
4
by: Tony Lownds | last post by:
(Note: PEPs in the 3xxx number range are intended for Python 3000) PEP: 3107 Title: Function Annotations Version: $Revision: 53169 $ Last-Modified: $Date: 2006-12-27 20:59:16 -0800 (Wed, 27 Dec...
11
by: =?iso-8859-1?q?Erik_Wikstr=F6m?= | last post by:
struct foo { int i; }; int bar(foo& f) { return f.i++; } int main() { bar(foo());
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
0
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.