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

  • Thread starter =?ISO-8859-1?Q?Gregory_Pi=F1ero?=
  • Start date
?

=?ISO-8859-1?Q?Gregory_Pi=F1ero?=

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?
 
C

Christopher Subich

Gregory said:
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.
 
R

Rocco Moretti

This URL is always tossed out:

http://starship.python.net/crew/mwh/hacks/objectthink.html
All arguments are passed by reference, but in Python equality rebinds
the name.
Bingo

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.
 
I

infidel

in Python equality rebinds the name

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

Dennis Lee Bieber

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.
[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.
"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".


--
 
?

=?ISO-8859-1?Q?Gregory_Pi=F1ero?=

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


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.
"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".


--
============================================================== <
(e-mail address removed) | Wulfraed Dennis Lee Bieber KD6MOG <
(e-mail address removed) | Bestiaria Support Staff <
============================================================== <
Home Page: <http://www.dm.net/~wulfraed/ > <
Overflow Page: <http://wlfraed.home.netcom.com/ > <
 
D

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:
'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
 
R

Rocco Moretti

Gregory said:
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.
 
D

Dennis Lee Bieber

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)
--
 
D

Dennis Lee Bieber

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.


--
 
C

Christopher Subich

Dennis said:
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.
 
C

Christopher Subich

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

Good catch. I was thinking of it as the "equals" operator.
 
C

Christopher Subich

Rocco said:
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)
 
R

Rocco Moretti

Dennis said:
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.
 
?

=?ISO-8859-1?Q?Gregory_Pi=F1ero?=

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
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

Christopher said:
+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/hacks/objectthink.html
 
C

Christopher Subich

Gregory said:
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
 
T

Terry Reedy

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
 
T

Terry Reedy

Gregory Piñero said:
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
 
D

Dennis Lee Bieber

Christopher said:
+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).
--
 

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

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top