By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
425,992 Members | 934 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 425,992 IT Pros & Developers. It's quick & easy.

Passing arguments to function - (The fundamentals are confusing me)

P: n/a
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>

bool1=True
lst1=[1,2,3]

def func1(arg1): arg1.append(4)

def func2(arg1): arg1=False
func1(lst1)
lst1 [1,2,3,4]
func2(bool1)
bool1

True

</code>

Why does my list variable get changed for the rest of the program, but
my boolean variable doesn't. What am I not understanding?

--
Gregory Piñero
Chief Innovation Officer
Blended Technologies
(www.blendedtechnologies.com)
Aug 9 '05 #1
Share this Question
Share on Google+
20 Replies


P: n/a
Gregory Piñero wrote:
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:
All arguments are passed by reference, but in Python equality rebinds
the name.

<code>

bool1=True
lst1=[1,2,3]

def func1(arg1): arg1.append(4)
In C++, pretending it had dynamic typing, this would be equivalent to:
void func1( * arg1){
arg1->append(4);
}

def func2(arg1): arg1=False void func2 ( * arg2) {
arg2 = &(False);
Why does my list variable get changed for the rest of the program, but
my boolean variable doesn't. What am I not understanding?


In Python, "x = y" has a very definite meaning of "y is assigned to the
name of x." This change does not affect whatever was in x to start
with, and it certainly would not affect anything else which holds a
reference to the object formerly known as x.

In contrast, calling a function which mutates the object (like .append
on lists, or assignment by lst[index]=something) actually changes the
object itself, which is of course reflected by all other names that hold
a reference to the object.
Aug 9 '05 #2

P: n/a
Christopher Subich wrote:
Gregory Piñero wrote:
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:
This URL is always tossed out:

http://starship.python.net/crew/mwh/...jectthink.html
All arguments are passed by reference, but in Python equality rebinds
the name.
Bingo
Why does my list variable get changed for the rest of the program, but
my boolean variable doesn't. What am I not understanding?


Booleans are immutable, lists are mutable. You change (mutate) the same
list, but you are referencing a different (immutable) Bool
In Python, "x = y" has a very definite meaning of "y is assigned to the
name of x."


Change it to "the object referenced by y is assigned to the name of x",
and you're closer to the truth.
Aug 9 '05 #3

P: n/a
> in Python equality rebinds the name

Assignment (=) rebinds the name. Equality (==) is something else
entirely.

Aug 9 '05 #4

P: n/a
On Tue, 9 Aug 2005 10:53:15 -0400, Gregory Piñero <gr********@gmail.com>
declaimed the following in comp.lang.python:

<rhetorical> Is this the third time this week that this has come
up?
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:
They work just like they do everywhere else...

Read the manuals on mutable and immutable objects. (I'd suggest
language reference chapter 3 and 4, library reference chapter 2.3.6,
2.3.7)

"names" in Python are movable labels attached to objects; they
are not fixed locations in memory to which object are copied; hence they
do not behave like variables in traditional languages.

bool1=True
immutable object -- "bool1" is a label attached to a fixed
object
lst1=[1,2,3]
mutable object -- "lst1" is a label attached to a box
containing objects
def func1(arg1): arg1.append(4)

"arg1" is a label attached to whatever object was passed in...
.append is an operation that changes what is /inside/ that
object
def func2(arg1): arg1=False
"arg1" is a label attached to whatever was passed in...
Assignment (especially of an immutable object) takes that label
OFF of the object that was passed in, and moves it the object of the
assignment. It does not move the label that is outside the call.
func1(lst1)
lst1 [1,2,3,4]

"lst1" is the label of the box; inside of func1, that box has
two labels: "lst1" and "arg1". You used the "arg1" label to locate the
box, and then you changed what was inside the box. Outside the function,
you used the "lst1" label to find the /same/ box and report what was
inside it.
func2(bool1)
bool1

True

"bool1" is the label of a non-box -- a "true". Inside the
function "true" has initially two labels: "bool1" and "arg1". You then
moved the "arg1" label from "true" to a different object "false".
"bool1" does not move, and still references the "true".
-- ================================================== ============ <
wl*****@ix.netcom.com | Wulfraed Dennis Lee Bieber KD6MOG <
wu******@dm.net | Bestiaria Support Staff <
================================================== ============ <
Home Page: <http://www.dm.net/~wulfraed/> <
Overflow Page: <http://wlfraed.home.netcom.com/> <

Aug 9 '05 #5

P: n/a
Ahh, so it's a mutable thing. That makes sense that I can't change a
mutable object and thus can't affect it outside of the function. Does
that mean Python functions aren't always byref, but are sometimes
byval for nonmutables?

-Greg
On 8/9/05, Dennis Lee Bieber <wl*****@ix.netcom.com> wrote:
On Tue, 9 Aug 2005 10:53:15 -0400, Gregory Piñero <gr********@gmail.com>
declaimed the following in comp.lang.python:

<rhetorical> Is this the third time this week that this has come
up?
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:

They work just like they do everywhere else...

Read the manuals on mutable and immutable objects. (I'd suggest
language reference chapter 3 and 4, library reference chapter 2.3.6,
2.3.7)

"names" in Python are movable labels attached to objects; they
are not fixed locations in memory to which object are copied; hence they
do not behave like variables in traditional languages.

bool1=True


immutable object -- "bool1" is a label attached to a fixed
object
lst1=[1,2,3]

mutable object -- "lst1" is a label attached to a box
containing objects
def func1(arg1): arg1.append(4)


"arg1" is a label attached to whatever object was passed in...
.append is an operation that changes what is /inside/ that
object
def func2(arg1): arg1=False

"arg1" is a label attached to whatever was passed in...
Assignment (especially of an immutable object) takes that label
OFF of the object that was passed in, and moves it the object of the
assignment. It does not move the label that is outside the call.
>func1(lst1)
>lst1

[1,2,3,4]

"lst1" is the label of the box; inside of func1, that box has
two labels: "lst1" and "arg1". You used the "arg1" label to locate the
box, and then you changed what was inside the box. Outside the function,
you used the "lst1" label to find the /same/ box and report what was
inside it.
>func2(bool1)
>bool1

True

"bool1" is the label of a non-box -- a "true". Inside the
function "true" has initially two labels: "bool1" and "arg1". You then
moved the "arg1" label from "true" to a different object "false".
"bool1" does not move, and still references the "true".


--
> ================================================== ============ <
> wl*****@ix.netcom.com | Wulfraed Dennis Lee Bieber KD6MOG <
> wu******@dm.net | Bestiaria Support Staff <
> ================================================== ============ <
> Home Page: <http://www.dm.net/~wulfraed/ > <
> Overflow Page: <http://wlfraed.home.netcom.com/ > <

--
http://mail.python.org/mailman/listinfo/python-list

--
Gregory Piñero
Chief Innovation Officer
Blended Technologies
(www.blendedtechnologies.com)
Aug 9 '05 #6

P: n/a
Dan
> Does that mean Python functions aren't always byref,
but are sometimes byval for nonmutables?


Don't think of it as byref or byval (as they are used in Visual Basic).
All parameters are passed the same way: by reference instead of by copy.

It's a little difficult to get your head around, but I promise that once
you understand it it will seem simple and intuitive.

def reassign(x):
x = ['foo']

"reassign" has no effect, even on a mutable type like a list. It simply
changes what "x" refers to, which isn't very useful because the name "x"
only exists inside the function.

In Python everything is treated the same way. Even integers are objects:
n = 1
n.__hex__()

'0x1'

What other programming languages do you know? Maybe we can draw a
comparison to something you're familiar with.

--
Presumably, we're all fully qualified computer nerds here,
so we are allowed to use "access" as a verb. Be advised,
however, that the practice in common usage drives
English-language purists to scowling fidgets.
- from Sybex's "Perl, CGI and JavaScript", p. 256
Aug 9 '05 #7

P: n/a
Gregory Piñero wrote:
Ahh, so it's a mutable thing. That makes sense that I can't change a
mutable object and thus can't affect it outside of the function.
If you meant "immutable" for the second mutable, you're right.
Does
that mean Python functions aren't always byref, but are sometimes
byval for nonmutables?


It'd probably do you good to get away from the by reference/by value
thinking. Python isn't C/Basic/Fortran/etc.

Variables in Python are names. They aren't the cubbyholes into which you
put values, they are sticky notes on the front of the cubby hole.

Parameter passing in Python always work the same way - you create a new
name pointing to the passed object. Fin.

The confusion you're having isn't in parameter passing, it's in the
difference between assignment and mutation. Mutation changes the object
itself (what's in the cubby hole), so it doesn't matter what or how many
names/variables it has (what sticky notes are on the front). Assigment
just changes where names point, not the contents of objects. (It's
moving that sticky note, and only that sticky note, from one cubby to a
different one.) Assignment justs affects that name, not any other name
which point to the same object, including the variables in the passing
scope.
Aug 9 '05 #8

P: n/a
On Tue, 09 Aug 2005 10:39:29 -0500, Rocco Moretti
<ro**********@hotpop.com> declaimed the following in comp.lang.python:

Change it to "the object referenced by y is assigned to the name of x",
and you're closer to the truth.
In a more simplistic view, I'd reverse the phrasing... The name
"x" is assigned to the object "y" (implying it is no longer attached to
whatever used to have the name)
-- ================================================== ============ <
wl*****@ix.netcom.com | Wulfraed Dennis Lee Bieber KD6MOG <
wu******@dm.net | Bestiaria Support Staff <
================================================== ============ <
Home Page: <http://www.dm.net/~wulfraed/> <
Overflow Page: <http://wlfraed.home.netcom.com/> <

Aug 9 '05 #9

P: n/a
On Tue, 9 Aug 2005 12:32:15 -0400, Gregory Piñero <gr********@gmail.com>
declaimed the following in comp.lang.python:
Ahh, so it's a mutable thing. That makes sense that I can't change a
mutable object and thus can't affect it outside of the function. Does
that mean Python functions aren't always byref, but are sometimes
byval for nonmutables?
Reverse: boolean constants are immutable and can not be changed,
you can only move the name used to access on to some other object.

If you want to try relating to Visual Basics "byref" "byval",
then they are neither. They are closer to a "copy reference"; changes to
the /reference copy/ do not propagate back out... Changes to the item
the reference, uh, references, do propagate out.

And it doesn't matter what they are referencing... If it is an
object that lets you "go inside to make changes" it is a mutable object,
and operations that "go inside" make no changes to the "reference"
itself.

def sample(l1, l2, l3):
l1.append(4)
l2 = [l2, 4]
l3[1] = 4

a = [1, 2]
b = [3, 4]
c = [5, 6]
sample(a, b, c)

The first line is NOT changing the l1 reference, it is going
inside l1 and changing the insides. "l1" and "a" BOTH reference a list
object that started with [1, 2]. The append opened that object, and
jammed the 4 into it... "a" and "l1" still reference the same list
object, but the list object now has [1, 2, 4]

The second line, OTOH, is changing the l2 reference; it is
creating a new list containing a reference to the object that l2 is
attached to and a reference to a constant 4, THEN it is saying the l2
NOW references the new list -- but since the name l2 only exists inside
the function, it doesn't affect the outside world... "l2" and "b"
initially reference the list object [3, 4]. The assignment first creates
a new list (with no references) of [reference to [3, 4], 4], then "l2"
is changed from a reference to [3, 4] to be a reference to [reference to
[3, 4], 4]; "b" is still a reference to [3, 4]

The third one, again, is opening the referenced object. "c" and
"l3" are references to a list containing [5, 6], "l3[1]" opens the list
and makes the second element 4. "l3" and "c" still reference the same
list.

Now, in that last, it may look like we are changing an immutable
integer. We are not. In all those lists where I have a simple integer:
[5, 6]
the actual list contents are:
[reference to 5, reference to 6]
so that third line is not changing the 6 to a 4, it changing the
"reference to 6" into a "reference to 4"

Names in Python are always (not just in function parameters)
references to objects. An assignment to a name itself always changes the
reference from the old object to a new object. Assignments to qualified
names (l3[1], l1.append(), etc.) are changing the references INSIDE the
object the name references (as long as that object is a mutable object),
but do not change the reference of the name.
-- ================================================== ============ <
wl*****@ix.netcom.com | Wulfraed Dennis Lee Bieber KD6MOG <
wu******@dm.net | Bestiaria Support Staff <
================================================== ============ <
Home Page: <http://www.dm.net/~wulfraed/> <
Overflow Page: <http://wlfraed.home.netcom.com/> <

Aug 9 '05 #10

P: n/a
Dennis Lee Bieber wrote:
In a more simplistic view, I'd reverse the phrasing... The name
"x" is assigned to the object "y" (implying it is no longer attached to
whatever used to have the name)


No, because that'd imply that the object 'y' somehow keeps track of the
names assigned to it, which is only true from a refcount perspective --
and only on some Python implementations at that. The object is the
property of the name, not vice versa.
Aug 9 '05 #11

P: n/a
infidel wrote:
in Python equality rebinds the name

Assignment (=) rebinds the name. Equality (==) is something else
entirely.


Good catch. I was thinking of it as the "equals" operator.
Aug 9 '05 #12

P: n/a
Rocco Moretti wrote:
Variables in Python are names. They aren't the cubbyholes into which you
put values, they are sticky notes on the front of the cubby hole.


+1 MOTW (Metaphor of the Week)
Aug 9 '05 #13

P: n/a
Dennis Lee Bieber wrote:
On Tue, 09 Aug 2005 10:39:29 -0500, Rocco Moretti
<ro**********@hotpop.com> declaimed the following in comp.lang.python:

Change it to "the object referenced by y is assigned to the name of x",
and you're closer to the truth.


In a more simplistic view, I'd reverse the phrasing... The name
"x" is assigned to the object "y" (implying it is no longer attached to
whatever used to have the name)


I guess I was too subtle - my point was lost. The key thing is not to
think of "the object 'y'" but to think of "the object referenced by
(named) 'y'" There is a distinction between the object (object) and the
name (variable), which is essential to eliminating the OP's conundrum.
Aug 9 '05 #14

P: n/a
Christopher Subich wrote:
Rocco Moretti wrote:
Variables in Python are names. They aren't the cubbyholes into which
you put values, they are sticky notes on the front of the cubby hole.

+1 MOTW (Metaphor of the Week)


Thanks, but please note it's not really mine - I've seen it somewhere
else before. I thought it was from the website I linked earlier[1], but
now I'm a little embarrased to find out that isn't, and I have no clue
where it's from.

[1] http://starship.python.net/crew/mwh/...jectthink.html
Aug 9 '05 #15

P: n/a
Thanks everyone. I understand now. Everything is a reference, all
that matters is whether I can go inside the "cubbyhole" and change
something. Immutables don't allow this.

So what if I do want to share a boolean variable like so:
<code>
sharedbool=True
class cls1:pass
cl=cls1()
cl.sharedbool1=sharedbool

sharedbool=False
cl.sharedbool1
True #but I wanted false!
</code>

My guess having read this threat would be to make a simple wrapper
class for a boolean so I'm changing something inside the object
instead of reassigning it?
<code>
class bigbool:
/t def __init__(self,tf):
/t/t self.val=tf
/t def setval(self,tf):
/t/t self.val=tf
</code>
Is there an easier way?
-Greg

On 8/9/05, Rocco Moretti <ro**********@hotpop.com> wrote: Christopher Subich wrote:
Rocco Moretti wrote:
Variables in Python are names. They aren't the cubbyholes into which
you put values, they are sticky notes on the front of the cubby hole.

+1 MOTW (Metaphor of the Week)


Thanks, but please note it's not really mine - I've seen it somewhere
else before. I thought it was from the website I linked earlier[1], but
now I'm a little embarrased to find out that isn't, and I have no clue
where it's from.

[1] http://starship.python.net/crew/mwh/...jectthink.html
--
http://mail.python.org/mailman/listinfo/python-list

--
Gregory Piñero
Chief Innovation Officer
Blended Technologies
(www.blendedtechnologies.com)
Aug 9 '05 #16

P: n/a
Gregory Piñero wrote:
So what if I do want to share a boolean variable like so:


Well, the easiest way is to wrap it in a list:

mybool = [True]
mybool[0] = False
mybool[0] = True

and so on.

Alternately, what is this boolean attached to that's so significant?
Sharing an arbitrary boolean, without any context, is rather strange --
perhaps it would be best to include both the boolean and associated
context in a single, larger object.

Also, remember that Python functions can return more than one value,
through implicit tuple packing and unpacking. This greatly reduces the
need for C-like result = function(&other_result) - isms.

def myfunc():
return 1,2,3
(a,b,c) = myfunc()
a == 1
b == 2
c == 3
Aug 9 '05 #17

P: n/a

"Christopher Subich" <sp****************@block.subich.spam.com> wrote in
message news:0S****************@bignews3.bellsouth.net...
Dennis Lee Bieber wrote:
In a more simplistic view, I'd reverse the phrasing... The name
"x" is assigned to the object "y" (implying it is no longer attached to
whatever used to have the name)

I agree that this is the more useful way to see it. I intentionally said
'useful' rather than 'correct' since I consider the former to be the way to
judge viewpoints. And I base the usefullness view on an informal (and yes,
unscientific) mental tabulation of newbie confusions posted to c.l.p over
several years. But better data could revise my judgment..
No, because that'd imply that the object 'y' somehow keeps track of the
names assigned to it,
I disagree with your implication and see it the other way. To me, 'the
object is bound to a name' implies that the object can only be bound to
one name while the name could have many objects bound to it, which is the
opposite of the case.

Analogy: in an elementary school, students are assigned to (bound to) a
room. The name=>room binding is recorded in a list (the 'namespace',
alphabetical for lookup of names) in the principal's office. The rooms do
not have to have a list of the students assigned to them, even though one
could be derived from the master list, as one could

Put another way: 'the name is bound' implies pretty clearly that the name
is acted up, and it is that acting upon that makes the object a (new)
property of the name. Nothing need be done to the object itself. This is
even clearer if 'bound' is expanded to 'associated with object-fetch
information'. So 'x = y' means "associated name 'x' with the object-fetch
information that name 'y' is currently associated with."
The object is the property of the name, not vice versa.


I agree, and see the binding of the name (to the object, as explained
above) as that which sets the property.

Terry J. Reedy


Aug 10 '05 #18

P: n/a

"Gregory Piñero" <gr********@gmail.com> wrote in message
news:31************************@mail.gmail.com...
Ahh, so it's a mutable thing. That makes sense that I can't change a
mutable object and thus can't affect it outside of the function.
You of course meant immutable, but this is still confused. It is a
name-binding versus object mutation thing.
Does that mean Python functions aren't always byref,
but are sometimes byval for nonmutables?


No, neither. Python functions calls are always by name binding. See my
first response. You are only about the 1000th or maybe 10000th person
confused by trying to apply inapplicable concepts to Python.

Terry J. Reedy


Aug 10 '05 #19

P: n/a
On Tue, 09 Aug 2005 13:39:08 -0500, Rocco Moretti
<ro**********@hotpop.com> declaimed the following in comp.lang.python:
Christopher Subich wrote:
Rocco Moretti wrote:
Variables in Python are names. They aren't the cubbyholes into which
you put values, they are sticky notes on the front of the cubby hole.

+1 MOTW (Metaphor of the Week)


Thanks, but please note it's not really mine - I've seen it somewhere
else before. I thought it was from the website I linked earlier[1], but
now I'm a little embarrased to find out that isn't, and I have no clue
where it's from.


I may not have been the first, but I've been using the simile of
Post-It Notes for Python for years now (since I typically run
X-NoArchive=Yes, Google won't have me -- though now that I've upgraded
to Agent 3.0 and nothing works the same, who knows)

The one time I didn't use that comparison, I got dinged (see
above where I discussed reversing the phrasing, so names "get assigned
to" object; to me that is putting the note ON the object, not that the
object suddenly knows about another name).
-- ================================================== ============ <
wl*****@ix.netcom.com | Wulfraed Dennis Lee Bieber KD6MOG <
wu******@dm.net | Bestiaria Support Staff <
================================================== ============ <
Home Page: <http://www.dm.net/~wulfraed/> <
Overflow Page: <http://wlfraed.home.netcom.com/> <

Aug 10 '05 #20

P: n/a
On Tue, 9 Aug 2005 15:18:39 -0400, Gregory Piñero <gr********@gmail.com>
declaimed the following in comp.lang.python:

So what if I do want to share a boolean variable like so:
<code>
sharedbool=True
class cls1:pass
cl=cls1()
cl.sharedbool1=sharedbool

sharedbool=False

cl.sharedbool1

True #but I wanted false!
</code>

Without the context for /why/ you want to share it, it is
difficult to guess...

Especially since, in your example, "cl.sharedbool1" is an
INSTANCE variable -- instance variables are, by definition, supposed to
be unique to each instance.

If you want /all/ instances of cls1 to share a variable, you
make it a class variable. If you just want the class to be able to
access something outside of itself, you might use "global" declarations.

If you're going that route, you might also want to define the
class to have the shared variable as a property, so retrieval and
setting correctly access the shared item.

-=-=-=-=-=-=-=-=
sharedBoolean = False

class Sharing(object):
def __init__(self):
pass
def _getSB(self):
global sharedBoolean
return sharedBoolean
def _setSB(self, nv):
global sharedBoolean
sharedBoolean = nv
return None
sharedBoolean = property(_getSB, _setSB)

s1 = Sharing()
s2 = Sharing()

print "Initial values"
print "sharedBoolean: ", sharedBoolean
print "s1: ", s1.sharedBoolean
print "s2: ", s2.sharedBoolean

sharedBoolean = True

print "Changed sharedBoolean itself"
print "sharedBoolean: ", sharedBoolean
print "s1: ", s1.sharedBoolean
print "s2: ", s2.sharedBoolean

s1.sharedBoolean = "Not a Boolean!"

print "Changed s1.sharedBoolean"
print "sharedBoolean: ", sharedBoolean
print "s1: ", s1.sharedBoolean
print "s2: ", s2.sharedBoolean
-=-=-=-=-=-=-=-=-=
Initial values
sharedBoolean: False
s1: False
s2: False
Changed sharedBoolean itself
sharedBoolean: True
s1: True
s2: True
Changed s1.sharedBoolean
sharedBoolean: Not a Boolean!
s1: Not a Boolean!
s2: Not a Boolean!

You could also use the property() mode to make instances access
a class variable (probably need to give it a different name), and not
need the global declarations.
-- ================================================== ============ <
wl*****@ix.netcom.com | Wulfraed Dennis Lee Bieber KD6MOG <
wu******@dm.net | Bestiaria Support Staff <
================================================== ============ <
Home Page: <http://www.dm.net/~wulfraed/> <
Overflow Page: <http://wlfraed.home.netcom.com/> <

Aug 10 '05 #21

This discussion thread is closed

Replies have been disabled for this discussion.