How to return a simple variable from a function (still newbie) ?

S

Stef Mientki

I want to return a "simple" variable from a function,
not using the function result.
Is that in any way possible ??

The code below is from O'Reilly, "Learning Python",
and there seems no way
to return a simple var like "z" in the example below.
Is that true ?

thanks,
Stef Mientki

<Python>
def some_function (z, y):
z = 2
y[2] = 'global ?'


x = 5
y = [1,2,3,4]
print x,y
some_function(x,y)
print x,y
</Python>
 
M

Marc 'BlackJack' Rintsch

I want to return a "simple" variable from a function, not using the
function result.
Why?

The code below is from O'Reilly, "Learning Python", and there seems no
way to return a simple var like "z" in the example below. Is that true ?

To return objects the ``return`` statement is used.
def some_function (z, y):
z = 2
y[2] = 'global ?'

Add:
return z

The string content seems to be a question. No `y` is not global here but
you modify the content of the object that's bound to the local name `y`.
Modifying an object is different from binding a name to a new object.
``y = ['uno', 'dos', 'tres']`` would not be visible outside the function.
x = 5
y = [1,2,3,4]
print x,y
some_function(x,y)

Change to:

x = some_function(x, y)

Ciao,
Marc 'BlackJack' Rintsch
 
P

Paul Hummer

How about restructuring your function like this:

def some_function( z,y ):
z = 2
y[2] = 'global ?'
return z

And then you'll have to react to the returning variable, like this in
your code:

x = 5
y = [1,2,3,4]
print x,y
print some_function( x, y )
print x,y

Now, it appears like you want some_function() to change x and y. It
doesn't really work that way. You'd have to either pass the variables
by reference into the function, or overwrite the existing values with
whatever the function returns. That might be beyond your scope now though.

Keep plugging, and welcome to Python!
 
C

Carsten Haese

I want to return a "simple" variable from a function,
not using the function result.
Is that in any way possible ??

The code below is from O'Reilly, "Learning Python",
and there seems no way
to return a simple var like "z" in the example below.
Is that true ?

thanks,
Stef Mientki

<Python>
def some_function (z, y):
z = 2
y[2] = 'global ?'


x = 5
y = [1,2,3,4]
print x,y
some_function(x,y)
print x,y
</Python>

Please reset your brain and read
http://effbot.org/zone/python-objects.htm , paying particular attention
to the section called "Assignment".

You should also think long and hard about *why* you want to return a
value from a function by modifying an input parameter instead of just
using the return statement. The "return by modifying an input parameter"
approach comes from C where that's the only way to return more than one
value from a function. In Python, no such crutch is necessary or
desirable.

With this in mind, the following quote seems appropriate:
"Trying to write C code using Python isn't going to be fun or
productive." -- Grant Edwards, comp.lang.python, 13 Sep 2006.

Hope this helps,

Carsten.
 
C

Carsten Haese

You'd have to either pass the variables by reference into the function, [...]

In Python, all function calls are call by reference. Period. The key
difference between Python and other programming languages is in the
behavior of the assignment statement.

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

In C/C++, assignments modify objects by copying the value from the right
hand side into the memory allocated to the object on the left hand side.

In Python, assignments modify namespaces by making the name on the left
hand side become a reference to the object on the right hand side. It is
irrelevant whether the name referred to some other object before the
assignment, and it is irrelevant whether that object is mutable or not.

The only way to achieve call-by-reference-like behavior in the
"assignment modifies objects" sense is by passing a reference to a
mutable object and then invoking the object's methods to mutate it.
Maybe that's what you meant, but that wasn't clear from what you said.

-Carsten
 
L

Laszlo Nagy

You should also think long and hard about *why* you want to return a
value from a function by modifying an input parameter instead of just
using the return statement. The "return by modifying an input parameter"
approach comes from C where that's the only way to return more than one
value from a function. In Python, no such crutch is necessary or
desirable.
Nobody mentioned the term for this. When a function changes its
parameters or its environment, then it is called a "side effect" and
generally it is considered harmful in all modern languages. ("Function"
here refers to a piece of code that is used to calculate one or more
values and provide these values to the caller.)

So you are trying to create a function that has a side effect. You
should not do this, unless you have a really good reason.

Regards,

Laszlo
 
S

Stef Mientki

Carsten said:
You'd have to either pass the variables by reference into the function, [...]

In Python, all function calls are call by reference. Period. The key
difference between Python and other programming languages is in the
behavior of the assignment statement.

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

In C/C++, assignments modify objects by copying the value from the right
hand side into the memory allocated to the object on the left hand side.

In Python, assignments modify namespaces by making the name on the left
hand side become a reference to the object on the right hand side. It is
irrelevant whether the name referred to some other object before the
assignment, and it is irrelevant whether that object is mutable or not.

The only way to achieve call-by-reference-like behavior in the
"assignment modifies objects" sense is by passing a reference to a
mutable object and then invoking the object's methods to mutate it.
Maybe that's what you meant, but that wasn't clear from what you said.

-Carsten
Laszlo, Carsten, Paul, Marc,
thanks for your valuable input,
I'm beginning to see the light, but it's still very dimmed.
Not only Python looks much more promising than MatLab,
but the also the Python newsgroup is much more helpfull than ... ;-)

Maybe one of you could give me hint to solve the next problem
(copied from one of my Matlab procedures ;-)
I can find a solution (= something that works) myself,
but I have the feeling this is completely the wrong way to go .

<Python>
# filter a chunk of a continuous signal IOI,
# so a continuous filtered signal is created.
# The function itself returns the filtered signal IOO,
# now to handle the chunks and create a continuous signal
# we must preserve a piece of history: "filter_prev"
# so this should either be an input and output variable

def chunk_Filter (filter_b, filter_a, Signal_IN, filter_prev):
Extended = r_ [filter_prev, Signal_IN]
filter_prev = Extended [ len(Signal_IN) : ]
Extended = signal.lfilter(filter_b, filter_a, Extended)
Signal_OUT = Extended [ len(filter_prev) : ]
return Signal_OUT

# call the function with actual parameters

IOO = chunk_Filter (BP_filter_b, BP_filter_a, IOI, BP_filter_prev)
</Python>

When I replace the assignment to "filter_prev", by a loop,
the function works as expected.
<Python>
#filter_prev = Extended [ len(Signal_IN) : ]
for i in range( len(filter_prev )):
filter_prev = Extended [ len(Signal_IN) + i ]
</Python>

I can not use a global variable here, because this function should be
called for several signals, each of course with it's own history.

thanks,
Stef
 
C

Carsten Haese

[...]
When I replace the assignment to "filter_prev", by a loop,
the function works as expected.
<Python>
#filter_prev = Extended [ len(Signal_IN) : ]
for i in range( len(filter_prev )):
filter_prev = Extended [ len(Signal_IN) + i ]
</Python>


Let's examine the fundamental difference between the statements

filter_prev = Extended [ len(Signal_IN) : ] and

filter_prev = Extended [ len(Signal_IN) + i ] .

The first statement is an assignment to the local name filter_prev.
Prior to that assignment, filter_prev was a reference to whatever object
was passed into your function in the fourth argument slot. The
assignment makes filter_prev become a reference to the list slice
Extended[len(Signal_IN):]. In no way does this affect the object that
filter_prev referred to previously.

The second statement looks a lot like an assignment, but it is not an
assignment. It is a method call. It is equivalent to the method call
filter_prev.__setitem__(i, Extended[len(Signal_IN)+i]), which is asking
the object that filter_prev refers to to change its i-th item. This does
affect the object that filter_prev refers to, which is of course the
same object that, in the global namespace, is known as BP_filter_prev.

The second approach has the desired side-effect of modifying the list
that was passed into the function. The first approach is unable to have
such an effect because assignments modify namespaces, not objects.
You're modifying the local namespace of the chunk_Filter function, and
that change is not made visible to the outside in any way.

If you wish to eliminate the for loop, you can do the following:

filter_prev[:] = Extended[len(Signal_IN):]

This, again, is not an assignment, even though it looks a lot like one.
It is equivalent to a __setslice__ method call, which modifies the
object that filter_prev refers to by making it replace its entire
contents with the contents of the list slice on the right hand side.

If you want to write functions with side-effects, you need to understand
the difference between

somename = someobject

on the one hand and

somename[something] = someobject or somename.something = someobject.

The first is an assignment. It means "make the name somename refer to
the object currently known as someobject". It does not matter if
somename currently refers to an object, and if it does refer to an
object, that object is not modified or even consulted in any way.

The second kind looks superficially like assignments, but they are in
fact __setitem__/__setslice__/__setattr__ method calls in disguise. For
them to succeed, somename must refer to an object that implements the
corresponding method, and those methods will cause the object known as
somename to modify itself.

After all that, you should now be sufficiently discouraged from
attempting to write functions with side effects. :) You can achieve the
same result without side-effects by returning more than one return value
from your function.

Hope this helps,

Carsten.
 
S

Stef Mientki

<snip> I'll hope to understand that later on !</snip>

You can achieve the
same result without side-effects by returning more than one return value
from your function.

Hope this helps,
Wow this certainly helps,
thanks very much Carsten!

Why is the obvious sometimes so far away ;-)

cheers,
Stef Mientki
 

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,776
Messages
2,569,603
Members
45,189
Latest member
CryptoTaxSoftware

Latest Threads

Top