Simple newbie question about parameters handling in functions (or am I dump or what?)

N

Niki Iv

I am totaly new to Python, although I have quite strong developer
background. Indeed I am evaluating Python to integrate it (Jython) in
my Java apps...
Well this is my first Python day. I am tampering with functions. I
read that parameters are passed by-value rather than by-reference. So
function can change wathever parameters reffers to. My troube (well my
presonal not understanding comes from this)

Example 1.
def ChangeList(ListToChange):
ListToChange[1] = "Line B"

MyList = ["Line 1","Line 2","Line 3"]
print MyList
ChangleList(MyList)
print MyList

Result is quite understandable (as in Pythin Bible is..)
["Line 1","Line 2","Line 3"]
["Line 1","Line B","Line 3"]

So now function ChangeList.. is
(1) def ChangeList(ListToChange):
(2) ListToChange[1] = "Line B"
(3) ListToChange[2] = "Line C"
(4) ListToChange = ["Line X","Line Y","Line Z"]

Result is the same (as it suppose to be..)
["Line 1","Line 2","Line 3"]
["Line 1","Line B","Line C"]


But now... I am swaping line
(1)def ChangeList(ListToChange):
(2) ListToChange[1] = "Line B"
(3) ListToChange = ["Line X","Line Y","Line Z"]
(4) ListToChange[2] = "Line C"


I have only swapped line 3 and 4.

Result is unexpected
["Line 1","Line 2","Line 3"]
["Line 1","Line B","Line 3"]

The last line in function is to change where ListToChange[2] reffers
to.. but string is the same..
Frankly I was expecting that ListToChange will change it's second
(zero base) element... but it does not.
Why?
Excuse me if the question is stupid.
 
N

Nuff Said

I am totaly new to Python, although I have quite strong developer
background. Indeed I am evaluating Python to integrate it (Jython) in
my Java apps...
Well this is my first Python day. I am tampering with functions. I
read that parameters are passed by-value rather than by-reference. So
function can change wathever parameters reffers to. My troube (well my
presonal not understanding comes from this)

Observe that there are mutable and immutable objects in Python and that
the *value* in Python's 'call by value' is always an *object reference*.
The following excerpt from the Python tutorial describes this:

The actual parameters (arguments) to a function call are
introduced in the local symbol table of the called function
when it is called; thus, arguments are passed using call by
value (where the value is always an object reference, not the
value of the object).

(Actually, 'call by object reference' would be a better description,
since if a mutable object is passed, the caller will see any changes
the callee makes to it (items inserted into a list).)

[http://www.python.org/doc/2.3.3/tut/node6.html]

HTH / Nuff
 
M

Mike C. Fletcher

Niki said:
I am totaly new to Python, although I have quite strong developer
background. Indeed I am evaluating Python to integrate it (Jython) in
my Java apps...
Well this is my first Python day. I am tampering with functions. I
read that parameters are passed by-value rather than by-reference. So
function can change wathever parameters reffers to. My troube (well my
presonal not understanding comes from this)
Actually, your trouble comes from whoever described the Python's
parameter-passing methodology in a way which is likely to confuse you.
Better not to use incompatible terms than to stretch them to describe a
different methodology.

Simply put, Python passes object references, and its names are just
references to objects. If you're a C/C++ person, Python objects are
conceptually passed as PyObject pointers (with the same semantics in
Jython, though not the same implementation). When you pass a parameter
into a function you're just binding a name (object reference) in the
function to a given object. When you re-bind that name within the
function you're just pointing the name (object reference) at the other
object, it has no effect on the original object (save reducing the
number of references to it).
Example 1.
def ChangeList(ListToChange):
ListToChange[1] = "Line B"

....

So now function ChangeList.. is
(1) def ChangeList(ListToChange):
(2) ListToChange[1] = "Line B"
(3) ListToChange[2] = "Line C"
(4) ListToChange = ["Line X","Line Y","Line Z"]
Your last line is doing nothing useful. It binds the name ListToChange
(which is never referred to after this point) to a newly constructed
list object. This doesn't affect the original list passed into the
function in any way.
Result is the same (as it suppose to be..)
["Line 1","Line 2","Line 3"]
["Line 1","Line B","Line C"]


But now... I am swaping line
(1)def ChangeList(ListToChange):
(2) ListToChange[1] = "Line B"
(3) ListToChange = ["Line X","Line Y","Line Z"]
(4) ListToChange[2] = "Line C"
Line 3 there is binding ListToChange to a new object, so line 4 is
operating on that new list object, not the original object. You don't
return the new list object, so the last two lines are doing nothing.
I have only swapped line 3 and 4.

Result is unexpected
["Line 1","Line 2","Line 3"]
["Line 1","Line B","Line 3"]

The last line in function is to change where ListToChange[2] reffers
to.. but string is the same..
Frankly I was expecting that ListToChange will change it's second
(zero base) element... but it does not.
Why?
Excuse me if the question is stupid.
Not stupid. Just based on a poor description of how Python's argument
passing works. Hope this one was somewhat more enlightening.

Have fun,
Mike

_______________________________________
Mike C. Fletcher
Designer, VR Plumber, Coder
http://members.rogers.com/mcfletch/
 
P

Peter Otten

Niki said:
I am totaly new to Python, although I have quite strong developer
background. Indeed I am evaluating Python to integrate it (Jython) in
my Java apps...
Well this is my first Python day. I am tampering with functions. I
read that parameters are passed by-value rather than by-reference. So
function can change wathever parameters reffers to. My troube (well my
presonal not understanding comes from this)

Example 1.
def ChangeList(ListToChange):
ListToChange[1] = "Line B"

MyList = ["Line 1","Line 2","Line 3"]
print MyList
ChangleList(MyList)
print MyList

Result is quite understandable (as in Pythin Bible is..)
["Line 1","Line 2","Line 3"]
["Line 1","Line B","Line 3"]

So now function ChangeList.. is
(1) def ChangeList(ListToChange):
(2) ListToChange[1] = "Line B"
(3) ListToChange[2] = "Line C"
(4) ListToChange = ["Line X","Line Y","Line Z"]

Result is the same (as it suppose to be..)
["Line 1","Line 2","Line 3"]
["Line 1","Line B","Line C"]

Strange. Most newbies would expect ["Line X","Line Y","Line Z"] (abreviated
[XYZ] hereafter). If you want to change the original list to [XYZ] at once,
do

ListToChange[:] = ["Line X", "Line Y", "Line Z"]

instead.
But now... I am swaping line
(1)def ChangeList(ListToChange):
(2) ListToChange[1] = "Line B"
(3) ListToChange = ["Line X","Line Y","Line Z"]
(4) ListToChange[2] = "Line C"

In (3) you are rebinding the local identifier ListToChange to the new [XYZ]
list. Every change that follows affects this list, so at the end of the
function you throw away the [XYC] list. You can easily verify that by
inserting a print statement into the function. By the way, wouldn't that be
the same in Java? If you think of Python as an "all pointers" language, you
should get it mostly right.
I have only swapped line 3 and 4.

(1) animal = Monkey()
(2) animal.eatBanana()
(3) animal = Bird()
(4) animal.layEgg()

Expect to see strange things happen if you change lines 3 and 4 :)
ListToChange = [...] has the same structure as my (3) - except that you
stuck to the same type while I switched to make it more obvious.

Peter
 
A

anton muhin

Niki said:
I am totaly new to Python, although I have quite strong developer
background. Indeed I am evaluating Python to integrate it (Jython) in
my Java apps...
Well this is my first Python day. I am tampering with functions. I
read that parameters are passed by-value rather than by-reference. So
function can change wathever parameters reffers to. My troube (well my
presonal not understanding comes from this)
You're wrong: in Python you pass references to objects.
Example 1.
def ChangeList(ListToChange):
ListToChange[1] = "Line B"
Now you change the second element of list that is referenced by
ListToChange identfier
MyList = ["Line 1","Line 2","Line 3"]
print MyList
ChangleList(MyList)
print MyList

Result is quite understandable (as in Pythin Bible is..)
["Line 1","Line 2","Line 3"]
["Line 1","Line B","Line 3"]

So now function ChangeList.. is
(1) def ChangeList(ListToChange):
(2) ListToChange[1] = "Line B"
(3) ListToChange[2] = "Line C"
(4) ListToChange = ["Line X","Line Y","Line Z"]
Attention: (4) rebinds variable ListToChange to new list ["Line X","Line
Y","Line Z"]. However, statemets (2) and (3) modified 2nd and 3rd
elements of passed list and you don't see a bug.
Result is the same (as it suppose to be..)
["Line 1","Line 2","Line 3"]
["Line 1","Line B","Line C"]


But now... I am swaping line
(1)def ChangeList(ListToChange):
(2) ListToChange[1] = "Line B"
(3) ListToChange = ["Line X","Line Y","Line Z"]
(4) ListToChange[2] = "Line C"
And here comes a trap: in (3) you rebind ListToChange and (4) modifies
new list.

You can use id function to track objects:

(1) def ChangeList(ListToChange):
(2) ListToChange[1] = "Line B"; print id(ListToChange)
(3) ListToChange[2] = "Line C"; print id(ListToChange)
(4) ListToChange = ["Line X","Line Y","Line Z"]; print id(ListToChange)


(1) def ChangeList(ListToChange):
(2) ListToChange[1] = "Line B"; print id(ListToChange)
(3) ListToChange = ["Line X","Line Y","Line Z"]; print id(ListToChange)
(4) ListToChange[2] = "Line C"; print id(ListToChange)

And another note: you may read more on mutable and immutable types as
well, because it's usual source of confusion for Python newcomers.

And the last note: IMHO, modification of passed parameters isn't really
Pythonic (again, IMHO) --- it's common thing in C++ and alike languages
where function can return only single value, but in Python you can
return multiply values and shouldn't modify passed parameters. Of
course, there might be situations where modification is really must, but
I'd try to avoid them.

regards,
anton.
 
A

Aahz

Well this is my first Python day. I am tampering with functions. I
read that parameters are passed by-value rather than by-reference. So
function can change wathever parameters reffers to. My troube (well my
presonal not understanding comes from this)

http://starship.python.net/crew/mwh/hacks/objectthink.html
--
Aahz ([email protected]) <*> http://www.pythoncraft.com/

"The joy of coding Python should be in seeing short, concise, readable
classes that express a lot of action in a small amount of clear code --
not in reams of trivial code that bores the reader to death." --GvR
 
T

Tim Roberts

Niki Iv said:
Well this is my first Python day. I am tampering with functions. I
read that parameters are passed by-value rather than by-reference. So
function can change wathever parameters reffers to. My troube (well my
presonal not understanding comes from this)

There were several responses to your post that pointed to articles that
will explain the technical details, but I decided to point out exactly
where your assumption goes wrong.
MyList = ["Line 1","Line 2","Line 3"]
print MyList
ChangleList(MyList)
print MyList

You need to separate the notion of "an object" from the notion of "a name".
Here, you create a list object that contains three strings. You have a
name called MyList that is bound to that list. When you call ChangeList,
you are passing that three-element list object to the function.
(1)def ChangeList(ListToChange):
(2) ListToChange[1] = "Line B"
(3) ListToChange = ["Line X","Line Y","Line Z"]
(4) ListToChange[2] = "Line C"

At line (1), the local name ListToChange will be bound to the same
three-element list that is bound to MyList. Both names are bound to the
same list. Line (2) alters the second element of that list.

In line (3), however, you create a brand new list object with three string
elements, and bind that object to the name "ListToChange". There are now
two separate three-element list objects, and this function no longer has
any link to the list that is bound to the global MyList. In line (4),
then, we alter the third element of this new list. MyList remains
unchanged. The function ends without doing anything with ListToChange, so
the new list (which contains ["Line X","Line Y","Line C"]) will be deleted
during garbage collection.
Result is unexpected
["Line 1","Line 2","Line 3"]
["Line 1","Line B","Line 3"]

The last line in function is to change where ListToChange[2] reffers
to.. but string is the same..
Frankly I was expecting that ListToChange will change it's second
(zero base) element... but it does not.

Sure, it does! Print ListToChange at the end of your function, and you'll
see that. However, ListToChange at that point is bound to a brand-new
list, so altering it has no global effect.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,014
Latest member
BiancaFix3

Latest Threads

Top