472,119 Members | 1,589 Online

# A new to Python question

Hi I'm trying to teach myself python and so far to good, but I'm having
a bit of trouble getting a function to work the way I think it should
work. Right now I'm taking a simple program I wrote in Fortran and
trying to do it in Python. I got it to work, but now I'm trying to
modularize it. My fortran program uses a subroutine and I was trying
to do the same thing in Python. But I'm still new so I'm having
trouble understanding what I'm doing wrong. Here is my code:

#! /usr/bin/python
#This program takes two vectors and multiplies them
#against a 10X10 array. It also then gives the dot product,
#sum, and max value of the array.

import Numeric
def abc(array1,array2,dotprod,sum,maxvalue):
"""Takes two arrays and performs predetermined calculations,
Then returns the solutions back as the same array, along
with the dot product, sum, and max value of the array."""
#TODO: Get this damn thing working!!
print "Array 1 in:",array1 #Debug
data = Numeric.zeros((10,10))
for i in range(10):
for j in range(10):
data[i,j] = (i+1)+(j+1)

e = Numeric.matrixmultiply(data, array1)
g = Numeric.matrixmultiply(Numeric.transpose(data),arr ay2)
array1 = e
array2 = g
dotprod = Numeric.dot(array1,array2)
sum = Numeric.sum(array1)
maxvalue = array2[Numeric.argmax(array2)]
print "Array 1 out:",array1 #Debug

return array1,array2,dotprod,sum,maxvalue #<<-- Not working as I
thought it would.

x = Numeric.arange(1,11)
y = Numeric.arange(1,11)*2
dotp,sumx,maxv = 0,0,0 #Is this the only way to declare a variable?

print 'Array X:',x
print 'Array Y:',y
abc(x,y,dotp,sumx,maxv)
print 'Calling function abc'
print 'Array X:',x
print 'Array Y:',y
print 'Dot Product of X and Y:',dotp
print 'Sum of array X:',sumx
print 'Max value of array Y:',maxv

If you run it the data gets passed to the function just fine and it
finds the right numbers. Its just getting it to pass them back thats
not working. I put some print statements inside the function just to
see how the data gets passed. So any ideas that would help me? If you
want to see the fortran code just email me.

David

Jul 19 '05 #1
32 2418
On 2005-05-14, David wrote:
abc(x,y,dotp,sumx,maxv)

(x,y,dotp,sumx,maxv) = abc(x,y,dotp,sumx,maxv)

Bernd

--
Those who desire to give up freedom in order to gain security,
will not have, nor do they deserve, either one. [T. Jefferson]
Jul 19 '05 #2
Hi,

You're thinking you're passing the arguments as reference (look at mutable
vs non-mutable)

Your function returns the values in a tupple (x,y,...); you need to fetch
the values from that tupple

Regards,

Philippe

David wrote:
Hi I'm trying to teach myself python and so far to good, but I'm having
a bit of trouble getting a function to work the way I think it should
work. Right now I'm taking a simple program I wrote in Fortran and
trying to do it in Python. I got it to work, but now I'm trying to
modularize it. My fortran program uses a subroutine and I was trying
to do the same thing in Python. But I'm still new so I'm having
trouble understanding what I'm doing wrong. Here is my code:

#! /usr/bin/python
#This program takes two vectors and multiplies them
#against a 10X10 array. It also then gives the dot product,
#sum, and max value of the array.

import Numeric
def abc(array1,array2,dotprod,sum,maxvalue):
"""Takes two arrays and performs predetermined calculations,
Then returns the solutions back as the same array, along
with the dot product, sum, and max value of the array."""
#TODO: Get this damn thing working!!
print "Array 1 in:",array1 #Debug
data = Numeric.zeros((10,10))
for i in range(10):
for j in range(10):
data[i,j] = (i+1)+(j+1)

e = Numeric.matrixmultiply(data, array1)
g = Numeric.matrixmultiply(Numeric.transpose(data),arr ay2)
array1 = e
array2 = g
dotprod = Numeric.dot(array1,array2)
sum = Numeric.sum(array1)
maxvalue = array2[Numeric.argmax(array2)]
print "Array 1 out:",array1 #Debug

return array1,array2,dotprod,sum,maxvalue #<<-- Not working as I
thought it would.

x = Numeric.arange(1,11)
y = Numeric.arange(1,11)*2
dotp,sumx,maxv = 0,0,0 #Is this the only way to declare a variable?

print 'Array X:',x
print 'Array Y:',y
abc(x,y,dotp,sumx,maxv)
print 'Calling function abc'
print 'Array X:',x
print 'Array Y:',y
print 'Dot Product of X and Y:',dotp
print 'Sum of array X:',sumx
print 'Max value of array Y:',maxv

If you run it the data gets passed to the function just fine and it
finds the right numbers. Its just getting it to pass them back thats
not working. I put some print statements inside the function just to
see how the data gets passed. So any ideas that would help me? If you
want to see the fortran code just email me.

David

Jul 19 '05 #3
On 2005-05-14, Philippe C. Martin wrote:
You're thinking you're passing the arguments as reference

That is the way Fortran handles them:

[...]
Right now I'm taking a simple program I wrote in Fortran

Bernd

--
Those who desire to give up freedom in order to gain security,
will not have, nor do they deserve, either one. [T. Jefferson]
Jul 19 '05 #4
David wrote:
Hi I'm trying to teach myself python and so far to good, but I'm having a bit of trouble getting a function to work the way I think it should
work. Right now I'm taking a simple program I wrote in Fortran and
trying to do it in Python. I got it to work, but now I'm trying to
modularize it. My fortran program uses a subroutine and I was trying
to do the same thing in Python. But I'm still new so I'm having
trouble understanding what I'm doing wrong. Here is my code:

#! /usr/bin/python
#This program takes two vectors and multiplies them
#against a 10X10 array. It also then gives the dot product,
#sum, and max value of the array.

import Numeric
def abc(array1,array2,dotprod,sum,maxvalue):
"""Takes two arrays and performs predetermined calculations,
Then returns the solutions back as the same array, along
with the dot product, sum, and max value of the array."""
#TODO: Get this damn thing working!!
print "Array 1 in:",array1 #Debug
data = Numeric.zeros((10,10))
for i in range(10):
for j in range(10):
data[i,j] = (i+1)+(j+1)

e = Numeric.matrixmultiply(data, array1)
g = Numeric.matrixmultiply(Numeric.transpose(data),arr ay2)
array1 = e
array2 = g
dotprod = Numeric.dot(array1,array2)
sum = Numeric.sum(array1)
maxvalue = array2[Numeric.argmax(array2)]
print "Array 1 out:",array1 #Debug

return array1,array2,dotprod,sum,maxvalue #<<-- Not working as I
thought it would.

x = Numeric.arange(1,11)
y = Numeric.arange(1,11)*2
dotp,sumx,maxv = 0,0,0 #Is this the only way to declare a variable?

print 'Array X:',x
print 'Array Y:',y
abc(x,y,dotp,sumx,maxv)
print 'Calling function abc'
print 'Array X:',x
print 'Array Y:',y
print 'Dot Product of X and Y:',dotp
print 'Sum of array X:',sumx
print 'Max value of array Y:',maxv

If you run it the data gets passed to the function just fine and it
finds the right numbers. Its just getting it to pass them back thats
not working. I put some print statements inside the function just to
see how the data gets passed. So any ideas that would help me? If you want to see the fortran code just email me.

David
Hello David,
welcome to Python!
Python always returns 'something' from a function or method if nothing
is specified or there is no return you get an implicit None.
You have created a function that accepts a few arguments and processes
them then returns there value.
The problem is that you **have not** used the return values ;)
example:

def funk(first,second,third):
return first,second,third

This can be like this:
print funk("theses three args can be anything",2,"three")

If you need to use the return values you need to assign them to a
"name" so you have a handle on them.
Variables are don't exist in Python there are only objects and names(
hence namespaces ), but not everyone is so strict and you still see
mention of 'variables' when they mean 'names'. ##dotp,sumx,maxv = 0,0,0 # not needed here
print 'Array X:',x
print 'Array Y:',y
## Notice we assign the return values to names so we can access it later arr1,arr2,dotp,sumx,maxv = abc(x,y,0,0,0)
print 'Calling function abc'
print 'Array X:',arr1
print 'Array Y:',arr2
print 'Dot Product of X and Y:',dotp
print 'Sum of array X:',sumx
print 'Max value of array Y:',maxv
Or you could pack all return values into a tuple and access it thru
slices. ##dotp,sumx,maxv = 0,0,0 # not needed here
print 'Array X:',x
print 'Array Y:',y
abcinfo = abc(x,y,0,0,0)
print 'Calling function abc'
print 'Array X:',abcinfo[0]
print 'Array Y:',abcinfo[1]
print 'Dot Product of X and Y:',abcinfo[2]
print 'Sum of array X:',abcinfo[3]
print 'Max value of array Y:',abcinfo[4]

Or you could use a dictionary, or etc...
The possibilities are endless.
Be sure to study up on namespaces, it will ease your Python woes.
Namespaces are the most fundamental part of Python that new users don't
understand. Namespace mastery will take you far.
Just remember there are only two scopes local and global ;)
http://docs.python.org
hth,
M.E.Farmer

Jul 19 '05 #5
(x,y,dotp,sumx,maxv) = abc(x,y,dotp,sumx,maxv)
This will only create a tuple in memory that has no name to reference
it by!
How would you access the returned value?
If you want a tuple you need to assign all the return vales to a single
name.
mytup = abc(x,y,dotp,sumx,maxv)
M.E.Farmer

Jul 19 '05 #6
M.E.Farmer wrote:
(x,y,dotp,sumx,maxv) = abc(x,y,dotp,sumx,maxv)
This will only create a tuple in memory that has no name to reference
it by!

Huh? This binds the names "x", "y", "dotp", "sumx" and "maxv" to the
values returned by abc:

py> def abc(*args):
.... return args
....
py> (x,y,dotp,sumx,maxv) = abc(2,3,5,7,11)
py> x
2
py> y
3
py> dotp
5
py> sumx
7
py> maxv
11

Of course, the parentheses around x,y,dotp,sumx,maxv are unnecessary.

STeVe
Jul 19 '05 #7
Thank you very much. Tulpes are really neat now that I've looked at
them. So after just fixing it, I changed it up and I would like to
show it off now.

#! /usr/bin/python
#This program takes two vectors and multiplies them
#against a 10X10 array. It also then gives the dot product,
#sum, and max value of the array.

import Numeric
def abc(package):
"""Takes two arrays and performs predetermined calculations,
Then returns the solutions back as the same array, along
with the dot product, sum, and max value of the array.

Data slots:
0 - First Array
1 - Second Array
2 - Dot product
3 - Sum
4 - Max Value"""
f = Numeric.zeros((10,10))
for i in range(10):
for j in range(10):
f[i,j] = (i+1)+(j+1)

e = Numeric.matrixmultiply(f, package[0])
g = Numeric.matrixmultiply(Numeric.transpose(f),packag e[1])
package[0] = e
package[1] = g
package[2] = Numeric.dot(package[0],package[1])
package[3] = Numeric.sum(package[0])
package[4] = package[1][Numeric.argmax(package[1])]
return package

data = [Numeric.arange(1,11),Numeric.arange(1,11)*2,0,0,0]
#data = [Array X, Array Y, Dot product, Sum, Max Value]

print 'Array X:',data[0]
print 'Array Y:',data[1]

data = abc(data)

print 'Calling function abc'
print 'Array X:',data[0]
print 'Array Y:',data[1]
print 'Dot Product of X and Y:',data[2]
print 'Sum of array X:',data[3]
print 'Max value of array Y:',data[4]

I think its just wonderful now, but if you got any other suggestions,

David

Jul 19 '05 #8
Hmm don't know what happened. I guess the formatting got all chewed up.

Jul 19 '05 #9
On 2005-05-14, M.E.Farmer wrote: (x,y,dotp,sumx,maxv) = abc(x,y,dotp,sumx,maxv)
This will only create a tuple in memory that has no name to reference
it by!
Maybe. But it does not seem to hurt. And I am not sure the tupel _is_
really created in that situation.
How would you access the returned value?
If you want a tuple you need to assign all the return vales to a single
name.

We do not want the tuple.
Python 2.3.5 (#1, Apr 28 2005, 12:14:04)
[GCC 3.4.3-20050110 (Gentoo Linux 3.4.3.20050110-r2,
ssp-3.4.3.20050110-0, pie-
on linux2
def foo():
... return 1,2,3
...
(a,b,c)=foo()
print a,b,c 1 2 3
works.

Of course, you can omit the ():
a,b,c=foo()
print a,b,c

1 2 3

That makes no difference.

Bernd

--
Those who desire to give up freedom in order to gain security,
will not have, nor do they deserve, either one. [T. Jefferson]
Jul 19 '05 #10
Yes, I gathered.

We all get our habits from somewhere :-)

Regards,

Philippe

Bernd Nawothnig wrote:
On 2005-05-14, Philippe C. Martin wrote:
You're thinking you're passing the arguments as reference

That is the way Fortran handles them:

[...]
Right now I'm taking a simple program I wrote in Fortran

Bernd

Jul 19 '05 #11
David wrote:
Thank you very much. Tulpes are really neat now that I've looked at
them. So after just fixing it, I changed it up and I would like to
show it off now.

#! /usr/bin/python
#This program takes two vectors and multiplies them
#against a 10X10 array. It also then gives the dot product,
#sum, and max value of the array.

import Numeric
def abc(package):
"""Takes two arrays and performs predetermined calculations,
Then returns the solutions back as the same array, along
with the dot product, sum, and max value of the array.

Data slots:
0 - First Array
1 - Second Array
2 - Dot product
3 - Sum
4 - Max Value"""
f = Numeric.zeros((10,10))
for i in range(10):
for j in range(10):
f[i,j] = (i+1)+(j+1)

e = Numeric.matrixmultiply(f, package[0])
g = Numeric.matrixmultiply(Numeric.transpose(f),packag e[1])
package[0] = e
package[1] = g
package[2] = Numeric.dot(package[0],package[1])
package[3] = Numeric.sum(package[0])
package[4] = package[1][Numeric.argmax(package[1])]
return package

data = [Numeric.arange(1,11),Numeric.arange(1,11)*2,0,0,0]
#data = [Array X, Array Y, Dot product, Sum, Max Value]

print 'Array X:',data[0]
print 'Array Y:',data[1]

data = abc(data)

print 'Calling function abc'
print 'Array X:',data[0]
print 'Array Y:',data[1]
print 'Dot Product of X and Y:',data[2]
print 'Sum of array X:',data[3]
print 'Max value of array Y:',data[4]

I think its just wonderful now, but if you got any other suggestions,

It's still not very Pythonic. Don't bother putting outputs in the
argument list. There are some good use cases for doing so, but until
you've been writing Python code for a while and the Pythonic idioms come
naturally to you, you should probably resist the urge. Python is not
Fortran.

def abc(x, y):
...
e = Numeric.matrixmultiply(f, x)
g = Numeric.matrixmultiply(Numeric.transpose(f), y)
dotp = Numeric.dot(x, y)
sumx = Numeric.sum(x)
maxy = Numeric.maximum.reduce(y)
return e, g, dotp, sumx, maxy

x = Numeric.arange(1,11)
y = x*2

x, y, dotp, sumx, maxy = abc(x, y)

--
Robert Kern
rk***@ucsd.edu

"In the fields of hell where the grass grows high
Are the graves of dreams allowed to die."
-- Richard Harter

Jul 19 '05 #12
On Sat, 14 May 2005 20:38:26 +0200, Bernd Nawothnig <Be*************@t-online.de> wrote:
On 2005-05-14, M.E.Farmer wrote:

(x,y,dotp,sumx,maxv) = abc(x,y,dotp,sumx,maxv)
This will only create a tuple in memory that has no name to reference
it by!

Maybe. But it does not seem to hurt. And I am not sure the tupel _is_
really created in that situation.

One way to get insight into what a statement does is to disassemble its code, e.g.,
import dis
dis.dis(compile('(x,y,dotp,sumx,maxv) = abc(x,y,dotp,sumx,maxv)','','exec'))

18 CALL_FUNCTION 5
21 UNPACK_SEQUENCE 5
24 STORE_NAME 1 (x)
27 STORE_NAME 2 (y)
30 STORE_NAME 3 (dotp)
33 STORE_NAME 4 (sumx)
36 STORE_NAME 5 (maxv)
42 RETURN_VALUE

In the context of a function or module scope, those loads and stores will change
to optimized byte code ops like LOAD_FAST and STORE_FAST etc, but you can see what's
happening above. I.e., on return from the function call, the returned sequence (we know it's
a tuple in your example, but it could be some other sequence thing) is upacked and its elements
are bound to the individual names, just as individual "assignments" would do.

Regards,
Bengt Richter
Jul 19 '05 #13
I said exactly what I meant, the parentheses around the values creates
a tuple that you have no reference to! It also has a side effect of
binding the names inside the tuple to a value and placing them in the
local namespace( implicit tuple unpacking ). It might be the "same" as
no parens but it isn't very clear. If you want a tuple make it
explicit, if you want individual names make it explicit.
def f(q,w,e,r): .... return q,w,e,r
.... # diff names
a,b,c,d= f(1,2,3,4)# explicit tuple unpacking
dir() ['__builtins__', '__doc__', '__name__', 'a', 'b', 'c', 'd', 'f',
'shell'] del a,b,c,d
# where is the tuple
(a,b,c,d)= f(1,2,3,4)# implicit tuple unpacking !?
dir() ['__builtins__', '__doc__', '__name__', 'a', 'b', 'c', 'd', 'f',
'shell'] del a,b,c,d
# Where is the tuple (a,s,d,f)? There isn't one.
# assign to a single name ( don't do tuple unpacking )
tup=f(1,2,3,4)
dir()

['__builtins__', '__doc__', '__name__', 'f', 'shell', 'tup']
Now there is.
Steve since you are closer to expert than novice you understand the
difference.
I feel this can be confusing to newbies, maybe you disagree.
M.E.Farmer

Jul 19 '05 #14
I said exactly what I meant, the parantheses around the values creates
a tuple that you have no reference to! It also has a side effect of
binding the names inside the tuple to a value and placing them in the
local namespace. It might be the "same" but it isn't very clear. If you
want a tuple make it explicit, if you want individual names make it
explicit.
def f(q,w,e,r): .... return q,w,e,r
.... # diff names
a,b,c,d= f(1,2,3,4)# explicit tuple unpacking
dir() ['__builtins__', '__doc__', '__name__', 'a', 'b', 'c', 'd', 'f',
'shell'] del a,b,c,d
# where is the tuple
(a,b,c,d)= f(1,2,3,4)# implicit tuple unpacking !?
dir() ['__builtins__', '__doc__', '__name__', 'a', 'b', 'c', 'd', 'f',
'shell'] del a,b,c,d
# Where is the tuple (a,b,c,d)? There isn't one.
# assign to a single name ( don't do tuple unpacking )
tup=f(1,2,3,4)
dir()

['__builtins__', '__doc__', '__name__', 'f', 'shell', 'tup']
Now there is.
Steve since you are closer to expert than novice you understand the
difference.
I feel this can be confusing to newbies, maybe you disagree.
M.E.Farmer

Jul 19 '05 #15
M.E.Farmer wrote:
I said exactly what I meant, the parentheses around the values creates
a tuple that you have no reference to! It also has a side effect of
binding the names inside the tuple to a value and placing them in the
local namespace( implicit tuple unpacking ). It might be the "same" as
no parens but it isn't very clear. If you want a tuple make it
explicit, if you want individual names make it explicit.

It actually is the same, and I don't think implicit or explicit is the
difference you should be citing here. The parentheses are fully
optional -- they don't change the semantics at all:

py> t = (4, 5)
py> a = t
py> a is t
True
py> a = (b, c) = t
py> a is t
True
py> a = b, c = t
py> a is t
True

In all cases, "a" still gets assigned the tuple (4, 5). Whether or not
you put the parentheses around "b, c" is fully a matter of style.

I don't know the implementation enough to know whether or not a tuple is
actually created when "b" and "c" are bound to their values, but I'd be
willing to bet that whatever happens to "(b, c)" is exactly the same as
what happens to "b, c".

STeVe
Jul 19 '05 #16
Steven Bethard wrote:

I don't know the implementation enough to know whether or not a tuple is
actually created when "b" and "c" are bound to their values, but I'd be
willing to bet that whatever happens to "(b, c)" is exactly the same as
what happens to "b, c".

Some corroborating evidence:

py> def f(t):
.... (b, c) = t
....
py> def g(t):
.... b, c = t
....
py> import dis
py> dis.dis(f)
3 UNPACK_SEQUENCE 2
6 STORE_FAST 2 (b)
9 STORE_FAST 1 (c)
15 RETURN_VALUE
py> dis.dis(g)
3 UNPACK_SEQUENCE 2
6 STORE_FAST 2 (b)
9 STORE_FAST 1 (c)
15 RETURN_VALUE

They're both an UNPACK_SEQUENCE byte-code.

STeVe
Jul 19 '05 #17
On 14 May 2005 10:44:30 -0700, "M.E.Farmer" <me*****@hotmail.com> wrote:
[...]
Be sure to study up on namespaces, it will ease your Python woes.
Namespaces are the most fundamental part of Python that new users don't
understand. Namespace mastery will take you far.
Just remember there are only two scopes local and global ;)

I.e., there can be many different local and global scopes, not just one of each,
and since Python is a very dynamic language, existence of things can vary with
execution time and logic, so those scopes don't all have to exist at the same time,
or at all, nor persist until the program runs to its end. Also, ISTM "local" is probably
being stretched a little above to include nested scopes, which are a bit different
from either plain local or global in how you can access them.

I would second the advice to explore namespaces, and particularly attribute name spaces
such as are defined by classes. Attribute access and descriptors conspire to enable much
of the magic you can cook up with Python, as well as stuff that happens automatically.

In short, a whole unopened deluxe set of programming Legos is at your elbow, besides the
pieces you have encountered so far. Have fun ;-)

Regards,
Bengt Richter
Jul 19 '05 #18
On 14 May 2005 13:25:55 -0700, "M.E.Farmer" <me*****@hotmail.com> wrote:
I said exactly what I meant, the parentheses around the values creates
a tuple that you have no reference to! It also has a side effect of I don't understand what you are saying, or meaning ;-)
BTW, the function call has nothing to do with what happens on the left hand side
of the assignment. It is only the result of the function call that counts, so we
could as well use a literal or other expression. This is a matter of unpacking
a sequence according to the left hand target. E.g.,
iter([1,2,3]) <listiterator object at 0x02F8F68C> a,b,c = iter([1,2,3])
d,e,f = [1,2,3]
g,h,i = 'GHI'
[a,b,c,d,e,f,g,h,i] [1, 2, 3, 1, 2, 3, 'G', 'H', 'I']

Ok, now looking at the code for the assignment to a,b,c vs to (a,b,c):
import dis
dis.dis(compile('(a,b,c) = iter([1,2,3])','','exec')) 1 0 LOAD_NAME 0 (iter)
12 BUILD_LIST 3
15 CALL_FUNCTION 1
18 UNPACK_SEQUENCE 3
21 STORE_NAME 1 (a)
24 STORE_NAME 2 (b)
27 STORE_NAME 3 (c)
33 RETURN_VALUE dis.dis(compile('a,b,c = iter([1,2,3])','','exec')) 1 0 LOAD_NAME 0 (iter)
12 BUILD_LIST 3
15 CALL_FUNCTION 1
18 UNPACK_SEQUENCE 3
21 STORE_NAME 1 (a)
24 STORE_NAME 2 (b)
27 STORE_NAME 3 (c)
33 RETURN_VALUE

I don't see anything in the code about creating a tuple that you have no reference to.
To see the unpacking of "GHI" so as to get rid of the function call red herring:
dis.dis(compile('a,b,c = "GHI"','','exec')) 1 0 LOAD_CONST 0 ('GHI')
3 UNPACK_SEQUENCE 3
6 STORE_NAME 0 (a)
9 STORE_NAME 1 (b)
12 STORE_NAME 2 (c)
18 RETURN_VALUE dis.dis(compile('(a,b,c) = "GHI"','','exec')) 1 0 LOAD_CONST 0 ('GHI')
3 UNPACK_SEQUENCE 3
6 STORE_NAME 0 (a)
9 STORE_NAME 1 (b)
12 STORE_NAME 2 (c)
18 RETURN_VALUE

ISTM the assignment part starts with UNPACK_SEQUENCE and all the code looks the same.
BTW, UIAM it is the commas that define tuples, so the outermost parens are really expression
parens more than tuple syntax. But note that you can have nested tuple structure as target,
and that does change the unpacking code (and what it expects to have available to unpack):
(x,(y,z)) = 'XYZ' Traceback (most recent call last):
File "<stdin>", line 1, in ?
ValueError: too many values to unpack (x,(y,z)) = 'X','YZ'
x 'X' y 'Y' z 'Z' (x,(y,z)) = [1, [2,3]]
x 1 y 2 z 3 dis.dis(compile('(x,(y,z)) = 0','','exec')) 1 0 LOAD_CONST 0 (0)
3 UNPACK_SEQUENCE 2
6 STORE_NAME 0 (x)
9 UNPACK_SEQUENCE 2
12 STORE_NAME 1 (y)
15 STORE_NAME 2 (z)
21 RETURN_VALUE

Obviously we can't unpack the zero, but the code doesn't know
that until it tries it, so we can look at what the left hand side code is
independent of the right hand side.

binding the names inside the tuple to a value and placing them in the
local namespace( implicit tuple unpacking ). It might be the "same" as
no parens but it isn't very clear. If you want a tuple make it
explicit, if you want individual names make it explicit.

OTOH, you might want a mix:
a, tup, (b,c), d = ['A', ('a', 'tuple'), 'BC', 'Sandra']
a 'A' tup ('a', 'tuple') b 'B' c 'C' d 'Sandra'

Or with gratuitous _outer_ parens:
(a, tup, (b,c), d) = ['A', ('a', 'tuple'), 'BC', 'Sandra']
a 'A' tup ('a', 'tuple') b 'B' c 'C' d 'Sandra'
dis.dis(compile("a, tup, (b,c), d = ['A', ('a', 'tuple'), 'BC', 'Sandra']",'','exec'))

12 BUILD_LIST 4
15 UNPACK_SEQUENCE 4
18 STORE_NAME 0 (a)
21 STORE_NAME 1 (tup)
24 UNPACK_SEQUENCE 2
27 STORE_NAME 2 (b)
30 STORE_NAME 3 (c)
33 STORE_NAME 4 (d)
39 RETURN_VALUE

Regards,
Bengt Richter
Jul 19 '05 #19
>It actually is the same, and I don't think implicit or explicit is the
difference you should be citing here. Why not it is relevant and true that Python is doing an implicit
unpacking of the values in that unnamed tuple.
Quoting myself """It might be the "same" as
no parens but it isn't very clear. If you want a tuple make it
explicit, if you want individual names make it explicit."""
So as you say, maybe it is is fully a matter of style and apparently I
don't like that style!
They're both an UNPACK_SEQUENCE byte-code.

I have dissed it myself ;)
My argument, if you can call it that, is that it is not clear that
Python is going to do a tuple unpacking here or not !
You had to dis it to find out and you are not a newbie.
# extra fluff from pyshell
import dis
dis.dis(compile('(x,y,dotp,sumx,maxv) = abc(x,y,dotp,sumx,maxv)','','exec'))
0 SET_LINENO 0

3 SET_LINENO 1
24 CALL_FUNCTION 5
27 UNPACK_SEQUENCE 5
30 STORE_NAME 1 (x)
33 STORE_NAME 2 (y)
36 STORE_NAME 3 (dotp)
39 STORE_NAME 4 (sumx)
42 STORE_NAME 5 (maxv)
48 RETURN_VALUE dis.dis(compile('x,y,dotp,sumx,maxv = abc(x,y,dotp,sumx,maxv)','','exec'))
0 SET_LINENO 0

3 SET_LINENO 1
24 CALL_FUNCTION 5
27 UNPACK_SEQUENCE 5
30 STORE_NAME 1 (x)
33 STORE_NAME 2 (y)
36 STORE_NAME 3 (dotp)
39 STORE_NAME 4 (sumx)
42 STORE_NAME 5 (maxv)
48 RETURN_VALUE dis.dis(compile('tup = abc(x,y,dotp,sumx,maxv)','','exec')) 0 SET_LINENO 0

3 SET_LINENO 1
24 CALL_FUNCTION 5
27 STORE_NAME 6 (tup)
33 RETURN_VALUE

You may notice that the act of assigning the return values to a unnamed
tuple and a name have different semantics and that was the real point.
The problem is why should this be the same:

a,b,c=(1,2,3)

(a,b,c)=(1,2,3)

Seems weird, non-intuitive that a tuple unpacking and tuple creation
have the same bytecode.
So why is this done? What is the reason, I am sure there are a few ;)

p.s. I am leaving out for a while and will read/followup later if
needed. Thank you all for your time.
M.E.Farmer

Jul 19 '05 #20
M.E.Farmer wrote:
They're both an UNPACK_SEQUENCE byte-code.
I have dissed it myself ;)
My argument, if you can call it that, is that it is not clear that
Python is going to do a tuple unpacking here or not !

Hmm... Well, I wouldn't say that. I think it's quite clear that
Python's doing a tuple unpacking. Just like it always does anytime
there's a comma on the left-hand side of an assignment statement.

Note that there's nothing that forces you to write the unpack sequence
like a tuple display. You can write it like a list display too, and
Python will treat it identically:

py> def unpack_tuple(t):
.... [x, y] = t
....
py> dis.dis(unpack_tuple)
3 UNPACK_SEQUENCE 2
6 STORE_FAST 2 (x)
9 STORE_FAST 1 (y)
15 RETURN_VALUE

I don't know how UNPACK_SEQUENCE is implemented, but at least on the
Python level, no tuple or list is created in the unpacking process.
Seems weird, non-intuitive that a tuple unpacking and tuple creation
have the same bytecode.

Sorry, I don't understand. Why do you think this?

py> def create_tuple(x, y):
.... (x, y)
....
py> dis.dis(create_tuple)
6 BUILD_TUPLE 2
9 POP_TOP
13 RETURN_VALUE
py> def unpack_tuple(t):
.... x, y = t
....
py> dis.dis(unpack_tuple)
3 UNPACK_SEQUENCE 2
6 STORE_FAST 2 (x)
9 STORE_FAST 1 (y)
15 RETURN_VALUE

To me, it looks like tuple creation uses the BUILD_TUPLE op-code, and
tuple unpacking uses the UNPACK_SEQUENCE op-code. Could you explain
what you meant by "a tuple unpacking and tuple creation have the same
bytecode"?

STeVe
Jul 19 '05 #21
I explained what i meant in previous post there was nothing more than
just a discussion I have no real problem here just more of a sore point
in style for me. I feel that parens are quite overloaded and it can be
confusing to newbies.
But if the parens are just fluff then get rid of them, it is clearer *
at least to me * ;)
There are enough things wrapped in parens nowadays it is starting to
look like lisp.
BTW, UIAM it is the commas that define tuples, so the outermost parens are really >expressionparens more than tuple syntax.

Hadn't really thought of that way but it makes sense
w = 1,2,3
w.__doc__

"""tuple() -> an empty tuple
tuple(sequence) -> tuple initialized from sequence's items

If the argument is a tuple, the return value is the same object."""
M.E.Farmer

Jul 19 '05 #22
Ok I give up you have convinced me. Of what I am not sure ;)
Anyway I have always viewed :
a,b,c= (1,2,3)
as unpacking a tuple
and :
(a,b,c) = (1,2,3)
as creation of a tuple
It was a false assumption, I have used Python for years and have never
written an unpacking as:
(a,b,c) = (1,2,3)
I have always put parens around my tuples I always thought that a tuple
was a parens with at least one comma ;)
It is just not something I have done, it seems counter to my thinking ,
till I read from Bengt it is the commas that make the tuple not the
parens.
It all makes sense now, but if they are not needed I think they that
should be avoided for clarity.
Steve thanks for your time. I always learn a little from you ;)
M.E.Farmer

Jul 19 '05 #23

"M.E.Farmer" <me*****@hotmail.com> wrote in message
But if the parens are just fluff then get rid of them, it is clearer *
at least to me * ;)

While I find unnecessary parens on the right of '=' tolerable, I agree as
to the style preference.

Terry J. Reedy

Jul 19 '05 #24
M.E.Farmer wrote:
I said exactly what I meant, the parentheses around the values creates
a tuple that you have no reference to!

repeating it doesn't make you right; no extra tuple is created, and the
parens are part of the syntax:

If the target is a target list enclosed in parentheses or in square
brackets: The object must be a sequence with the same number
of items as there are targets in the target list, and its items are
assigned, from left to right, to the corresponding targets.

http://docs.python.org/ref/assignment.html

(originally, you had to use [] to unpack lists, and () or no parens only
worked for tuples. the ability to use an arbitrary sequence was added
in 1.5)

on the other hand, the function you're calling in this example *does*
create a tuple that you have no reference to after the assignment.
that doesn't matter, of course, since the tuple is removed by the
garbage collector immediately after it has been unpacked.

</F>

Jul 19 '05 #25
Bernd Nawothnig wrote:
You're thinking you're passing the arguments as reference

That is the way Fortran handles them:

which is one of the things you really love when you link against
underdocumented Fortran programs from C. ("is that parameter
a scalar or an array? crash! oh, an array. how many values does
it expect? crash! oh, a few more, I suppose").

</F>

Jul 19 '05 #26
On 2005-05-14, M.E.Farmer wrote:
I explained what i meant in previous post there was nothing more than
just a discussion
No. You claimed

<quote>
This will only create a tuple in memory
</quote>

But we just learned that this is not the case.
I have no real problem here just more of a sore point in style for
me. I feel that parens are quite overloaded and it can be confusing
to newbies. But if the parens are just fluff then get rid of them, it
is clearer * at least to me * ;)
Reduced to this argument I have no objection.
There are enough things wrapped in parens nowadays it is starting to
look like lisp.

Lisp is far from being ugly ;-)

Bernd

--
Those who desire to give up freedom in order to gain security,
will not have, nor do they deserve, either one. [T. Jefferson]
Jul 19 '05 #27
On Sun, 15 May 2005 08:00:47 +0200, "Fredrik Lundh" <fr*****@pythonware.com> wrote:
M.E.Farmer wrote:
I said exactly what I meant, the parentheses around the values creates
a tuple that you have no reference to!
repeating it doesn't make you right; no extra tuple is created, and the
parens are part of the syntax:

If the target is a target list enclosed in parentheses or in square
brackets: The object must be a sequence with the same number
of items as there are targets in the target list, and its items are
assigned, from left to right, to the corresponding targets.

http://docs.python.org/ref/assignment.html

(originally, you had to use [] to unpack lists, and () or no parens only
worked for tuples. the ability to use an arbitrary sequence was added
in 1.5)

Note that (x) without a comma doesn't unpack like [x] however:
(x)= 123,
x (123,) [x]= 123,
x 123 (x,)= 123,
x 123 x,= 123,
x 123

Also, BTW,
123, (123,) [123,]

[123]

I.e., that last result is not [(123,)]

There's actually a bunch of context-sensitive things about commas that
you just have to get used to, in lists, tuples, function call arg lists,
subscripts (__getitem__ args), unpacking assignment targets, etc.
on the other hand, the function you're calling in this example *does*
create a tuple that you have no reference to after the assignment. Yeah, but it would create that tuple whether there was an assignment
of the returned result or not. Collecting unconnected facts in one
breath remind me too much of political speeches ;-)that doesn't matter, of course, since the tuple is removed by the
garbage collector immediately after it has been unpacked.

I'm too tired to figure a humorous segue ;-)

Regards,
Bengt Richter
Jul 19 '05 #28
Fredrik Lundh wrote:
which is one of the things you really love when you link against
underdocumented Fortran programs from C. ("is that parameter
a scalar or an array? crash! oh, an array. how many values does
it expect? crash! oh, a few more, I suppose").

+1 QOTW

STeVe
Jul 19 '05 #29
No. You claimed <quote>
This will only create a tuple in memory
</quote>
That is not what I said please do not edit my words and call it a
quote!
But we just learned that this is not the case. Yes it seems I was proven wrong and have learned much from the
discussion ;)
That is why I am here to learn from others and help if I can (
sometimes I am just plain wrong and I get the help )
Reduced to this argument I have no objection. Glad to hear it.
Lisp is far from being ugly ;-)

Your words not mine.I never said it was ugly.
Lisp is beautiful but Python isn't Lisp, and the () *are* getting

M.E.Farmer

Jul 19 '05 #30
Fredrik and Bengt:
Thank you for the time.
I will study the docs and play with the shell till this is firm.
M.E.Farmer

Jul 19 '05 #31
On 2005-05-15, M.E.Farmer wrote:
No. You claimed <quote>
This will only create a tuple in memory
</quote>
That is not what I said please do not edit my words and call it a
quote!

Again the whole sentence:

| This will only create a tuple in memory that has no name to reference
| it by!

Please check it out. I did only cut the sentence. But that did not
change the sense of the part I quoted. (As I understood it, correct me
if I'm wrong, I'm not a native English speaker).
But we just learned that this is not the case.

Yes it seems I was proven wrong and have learned much from the
discussion ;) That is why I am here to learn from others and help if
I can ( sometimes I am just plain wrong and I get the help )

I know that very well. I often learned much from such discussions too.
Reduced to this argument I have no objection.

Lisp is far from being ugly ;-)

Your words not mine.I never said it was ugly.
Lisp is beautiful but Python isn't Lisp, and the () *are* getting

Understood and accepted.

Bernd

--
Those who desire to give up freedom in order to gain security,
will not have, nor do they deserve, either one. [T. Jefferson]
Jul 19 '05 #32
It looks like the docs could use some examples of the various
assignments it refers to.
I think something like Bengt posted would be a nice addition if it
included assignments with slices and dicts too.
Just a thought.
M.E.Farmer

Jul 19 '05 #33

### This discussion thread is closed

Replies have been disabled for this discussion.