var or inout parm?

M

mh

How can I make a "var" parm, where the called function can modify
the value of the parameter in the caller?

def f(x):
x = x + 1

n = 1
f(n)
# n should now be 2

Many TIA!!
Mark
 
C

Chris Rebert

How can I make a "var" parm, where the called function can modify
the value of the parameter in the caller?

Not directly possible or encouraged. You can emulate it by sticking
the value in a container object (e.g. list) though:

def f(x):
x[0] += 1 #non-augmented assignment would work too

n = [1]
f(n)
print n[0] #==> 2

Cheers,
Chris
 
D

Diez B. Roggisch

How can I make a "var" parm, where the called function can modify
the value of the parameter in the caller?

def f(x):
x = x + 1

n = 1
f(n)
# n should now be 2

Chris showed one way, another is simply returning it. As python can
return ad-hoc created tuples & unpack them, some C++-wrappers for
example treat out/inout vars like this:


def foo(in, inout):
return inout, out1, out2


x, y, z = foo(a, x)

Obviously you are responsible for properly assigning the returned inout
to the right name again.

Diez
 
S

Steven D'Aprano

How can I make a "var" parm, where the called function can modify the
value of the parameter in the caller?

By using another language.
def f(x):
x = x + 1

n = 1
f(n)
# n should now be 2

Python doesn't work like that. You should read this:

http://effbot.org/zone/python-objects.htm


Some work arounds, in order from worst-to-best:


(1) Use a hard-coded global name:


x = 1

def f():
global x
x = x + 1

f()
assert x == 2


(2) Wrap the value you want to change in a list, then modify the list in
place.

n = [1]

def f(alist):
alist[0] = alist[0] + 1

f(n)
assert n[0] == 2


(4) Just use an ordinary function. Functions can return multiple values.

n = 1

def f(x):
return (x+1, 99)

n, y = f(n)
assert y == 99
assert n == 2


(5) Find another way to solve your problem.

Why do you think you need var parameters? What problem are you hoping to
solve by using them? As a former Pascal programmer, I missed var
parameters at first, but now I don't.
 
C

Colin J. Williams

How can I make a "var" parm, where the called function can modify
the value of the parameter in the caller?

def f(x):
x = x + 1

n = 1
f(n)
# n should now be 2

Many TIA!!
Mark

Why not run it and see?

Your function returns None.

The function in effect takes a copy of
n. n is not changed.

Colin W.
 
B

Bruno Desthuilliers

Colin J. Williams a écrit :
Why not run it and see?

Your function returns None.

The function in effect takes a copy of n.

Nope, it takes the object bound to global name 'n'.
 
C

Chris Rebert

Colin J. Williams a écrit :

Nope, it takes the object bound to global name 'n'.

See Also: the earlier heated debate thread over what evaluation
strategy Python uses (Survey says!: call-by-object).

Cheers,
Chris
 
A

Aaron Brady

How can I make a "var" parm, where the called function can modify
the value of the parameter in the caller?

def f(x):
    x = x + 1

n = 1
f(n)
# n should now be 2

You can't. 'n' would need a 'set_to' method, which it doesn't have.
Otherwise, that's not what the equal sign does.
 
M

mh

Chris Rebert said:
Not directly possible or encouraged. You can emulate it by sticking
the value in a container object (e.g. list) though:

Thanks, that's just what I needed. I'm using this to monkeypatch
a test driver into some code that I can't touch, otherwise
I would just have the function return a tuple with the replacement
values.

Cheers!
Mark
 
J

J. Clifford Dyer

See Also: the earlier heated debate thread over what evaluation
strategy Python uses (Survey says!: call-by-object).

Oh dear God. PLEASE don't see also that thread. That way lies madness.
Just google for call-by-object, and ignore the hell out of that thread.
 
S

sturlamolden

How can I make a "var" parm, where the called function can modify
the value of the parameter in the caller?

def f(x):
x = x + 1

Short ansver:

You can modify function parameters if they are mutable. If they are
immutable any attempt to modify the parameter will trigger a copy.

You cannot modify parameters by rebinding. x = x + 1 is a rebinding. x
+= 1 is not.

If you need to modify immutable parameters or do the modification by
rebinding, pass the variable back. Python allows multiple return
values.
 
C

Chris Rebert

You cannot modify parameters by rebinding. x = x + 1 is a rebinding. x
+= 1 is not.

Python begs to differ, as those two statements are both semantically
identical in this case:

Python 2.6 (r26:66714, Nov 18 2008, 21:48:52)
[GCC 4.0.1 (Apple Inc. build 5484)] on darwin
Type "help", "copyright", "credits" or "license" for more information.8405348

If you were talking about lists rather than integers though, you'd be
absolutely correct, as the += ends up being a method call to __iadd__
instead of a plain assignment.

Cheers,
Chris
 
S

sturlamolden

Python begs to differ, as those two statements are both semantically
identical in this case:

That is because integers are immutable. When x += 1 is done on an int,
there will be a rebinding. But try the same on say, a numpy array, and
the result will be different:
10451488


Whereas:
10051232
 
S

sturlamolden

That is because integers are immutable. When x += 1 is done on an int,
there will be a rebinding. But try the same on say, a numpy array, and
the result will be different:


And a consequence of this is, if you have a function like

def foobar(x):
x += 1

then the parameter x will be modified given that x have mutable type.

However, if we have a function like

def foobar(x):
x = x + 1

then x will not be modified, mutable or not.

(Well, you could abuse operator overlaoding to make unexpected side
effects in the latter case. But except for such insanity it will not
have side-effects.)
 
S

Steve Holden

sturlamolden said:
And a consequence of this is, if you have a function like

def foobar(x):
x += 1

then the parameter x will be modified given that x have mutable type.

However, if we have a function like

def foobar(x):
x = x + 1

then x will not be modified, mutable or not.

(Well, you could abuse operator overlaoding to make unexpected side
effects in the latter case. But except for such insanity it will not
have side-effects.)
This was all thrashed out exhaustively in the still-feared call
semantics thread. Yes, augmented operations work differently on mutable
and immutable objects. Nothing to see here, move right along ...

regards
Steve
 
H

Hrvoje Niksic

sturlamolden said:
That is because integers are immutable. When x += 1 is done on an int,
there will be a rebinding. But try the same on say, a numpy array, and
the result will be different:

The result will be different, but a still occurs! You usually don't
notice it because augmented assignments with side effect are normally
careful to return the same object, so rebinding is a no-op. But in
some cases, that can byte you. For example, tupleobj[0] += 1 raises
an exception even when tupleobj[0] is mutable. Taking the numpy
example:
import numpy
t = (numpy.zeros(10),)
t (array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]),)
t[0] += 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

Of course, the side effect occurs before the exception, so:
array([ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])
 
S

sturlamolden

(array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]),)>>> t[0] += 1

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

Of course, the side effect occurs before the exception, so:
array([ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])


Actually I would consider this to be a bug. The tuple is immutable,
but no mutation of the tuple is ever attempted.

Sturla Molden
 

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,769
Messages
2,569,581
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top