Preferred method for "Assignment by value"

H

hall.jeff

As a relative new comer to Python, I haven't done a heck of a lot of
hacking around with it. I had my first run in with Python's quirky (to
me at least) tendency to assign by reference rather than by value (I'm
coming from a VBA world so that's the terminology I'm using). I was
surprised that these two cases behave so differently

test = [[1],[2]]
x = test[0]
x[0] = 5
test
x = 1
test

Now I've done a little reading and I think I understand the problem...
My issue is, "What's the 'best practise' way of assigning just the
value of something to a new name?"

i.e.
test = [[1,2],[3,4]]
I need to do some data manipulation with the first list in the above
list without changing <test>
obviously x = test[0] will not work as any changes i make will alter
the original...
I found that I could do this:
x = [] + test[0]

that gets me a "pure" (i.e. unconnected to test[0] ) list but that
concerned me as a bit kludgy

Thanks for you time and help.
 
G

Gary Herron

As a relative new comer to Python, I haven't done a heck of a lot of
hacking around with it. I had my first run in with Python's quirky (to
me at least) tendency to assign by reference rather than by value (I'm
coming from a VBA world so that's the terminology I'm using). I was
surprised that these two cases behave so differently

test = [[1],[2]]
x = test[0]
x[0] = 5
test
x = 1
test

Now I've done a little reading and I think I understand the problem...
My issue is, "What's the 'best practise' way of assigning just the
value of something to a new name?"

i.e.
test = [[1,2],[3,4]]
I need to do some data manipulation with the first list in the above
list without changing <test>
obviously x = test[0] will not work as any changes i make will alter
the original...
I found that I could do this:
x = [] + test[0]

that gets me a "pure" (i.e. unconnected to test[0] ) list but that
concerned me as a bit kludgy

Thanks for you time and help.

If you want a *copy* of an object (or portion thereof), you must
explicitly *specify* a copy. THere are different ways of doing that
depending on the object in question.

Lists (and slices thereof) can be copied to a new list withthe slice syntax:
L[1:4] will copy a limited portion, and
L[:] will copy the whole list.
The kind of copy is only one level deep -- the contents of the copy
will be references to the contents of L

Dictionaries have a copy method that creates a new dictionary.
Again this copy is only one level deep.

The copy modules provides a more general way to copy objects. It
provides the ability to produce both shallow and deep copies.

A small note: In a dozen years of programming in Python, I've used
these various copy methods perhaps a dozen times or less. If you find
you are copying structures often, you are probably not using Python as
effectively as you could.

Gary Herron
 
M

Matimus

As a relative new comer to Python, I haven't done a heck of a lot of
hacking around with it. I had my first run in with Python's quirky (to
me at least) tendency to assign by reference rather than by value (I'm
coming from a VBA world so that's the terminology I'm using). I was
surprised that these two cases behave so differently

test = [[1],[2]]
x = test[0]
x[0] = 5
test>>> [[5],[2]]

x = 1
test

Now I've done a little reading and I think I understand the problem...
My issue is, "What's the 'best practise' way of assigning just the
value of something to a new name?"

i.e.
test = [[1,2],[3,4]]
I need to do some data manipulation with the first list in the above
list without changing <test>
obviously x = test[0] will not work as any changes i make will alter
the original...
I found that I could do this:
x = [] + test[0]

that gets me a "pure" (i.e. unconnected to test[0] ) list but that
concerned me as a bit kludgy

Thanks for you time and help.


I think you understand the concept, basically you want to make a copy.

Ether of these are acceptable:
x = test[0][:]
OR
x = list(test[0])

this will also work:

import copy
x = copy(test[0])

Matt
 
A

Arnaud Delobelle

As a relative new comer to Python, I haven't done a heck of a lot of
hacking around with it. I had my first run in with Python's quirky (to
me at least) tendency to assign by reference rather than by value (I'm
coming from a VBA world so that's the terminology I'm using). I was
surprised that these two cases behave so differently

Perhaps it is better to think that you bind the name 'x' to the object
'42' when you write 'x=42'.
test = [[1],[2]]
x = test[0]
x[0] = 5
test>>> [[5],[2]]

x = 1
test

Now I've done a little reading and I think I understand the problem...
My issue is, "What's the 'best practise' way of assigning just the
value of something to a new name?"

i.e.
test = [[1,2],[3,4]]
I need to do some data manipulation with the first list in the above
list without changing <test>
obviously x = test[0] will not work as any changes i make will alter
the original...
I found that I could do this:
x = [] + test[0]

that gets me a "pure" (i.e. unconnected to test[0] ) list but that
concerned me as a bit kludgy

Thanks for you time and help.

To create a new list with the same elements as a sequence seq, you can
use list(seq). 'list' is the type of lists, it is also a 'constructor'
for list objects (the same goes for other common buit-in types, such
as 'int', 'float', 'str', 'tuple', 'dict').

E.g.
foo = [1, 2, 3]
bar = list(foo)
foo[0] = 4
foo [4, 2, 3]
foo = [1, 2, 3]
bar = list(foo)
bar[0] = 4
bar [4, 2, 3]
foo [1, 2, 3]

HTH
 
H

hall.jeff

Thank you both, the assigning using slicing works perfectly (as I'm
sure you knew it would)... It just didn't occur to me because it
seemed a little nonintuitive... The specific application was

def dicttolist (inputdict):
finallist=[]
for k, v in inputdict.iteritems():
temp = v
temp.insert(0,k)
finallist.append(temp)

return finallist

to convert a dictionary to a list. We deal with large amounts of
bankdata which the dictionary is perfect for since loan number is a
perfect key... at the end, though, I have to throw it into a csv file
and the csv writer doesn't like dictionaries (since the key is an
iterable string it iterates over each value in the key)

by changing temp = v[:] the code worked perfectly (although changing
temp.insert(0,k) to temp = [k] + temp also worked fine... I didn't
like that as I knew it was a workaround)

Thanks again for the help
 
H

hall.jeff

I think the fundamental "disconnect" is this issue of mutability and
immutability that people talk about (mainly regarding tuples and
whether they should be thought of as static lists or not)

Coming from VBA I have a tendency to think of everything as an
array...

So when I create the following

test=[1,2],[3,4],[5,6] I'm annoyed to find out that I can change do
the following
test[1][1] = 3
but i can't do
test[1] = [3,3]
and so I throw tuples out the window and never use them again...

The mental disconnect I had (until now) was that my original tuple was
in affect "creating" 3 objects (the lists) within a 4th object (the
tuple)... Previously, I'd been thinking of the tuple as one big object
(mentally forcing them into the same brain space as multi-dimensional
arrays in VBA)

This was a nice "aha" moment for me...
 
D

duncan smith

Thank you both, the assigning using slicing works perfectly (as I'm
sure you knew it would)... It just didn't occur to me because it
seemed a little nonintuitive... The specific application was

def dicttolist (inputdict):
finallist=[]
for k, v in inputdict.iteritems():
temp = v
temp.insert(0,k)
finallist.append(temp)

return finallist

Maybe,

finallist = [[k] + v for k, v in inputdict.iteritems()]

the list concatenation creating new lists.

Duncan
 
R

Robin Stocker

by changing temp = v[:] the code worked perfectly (although changing
temp.insert(0,k) to temp = [k] + temp also worked fine... I didn't
like that as I knew it was a workaround)

So the for body now looks like this?:

temp = v[:]
temp.insert(0, k)
finallist.append(temp)

It can still be clarified and simplified to this (may also be faster):

temp = [k] + v
finallist.append(temp)

Which one do you like better :)?

Robin
 
S

sturlamolden

test = [[1],[2]]
x = test[0]

Python names are pointer to values. Python behaves like Lisp - not
like Visual Basic or C#.

Here you make x point to the object which is currently pointed to by
the first element in the list test. If you now reassign test[0] = [2],
x is still pointing to [1].

x[0] = 5
test>>> [[5],[2]]

x = 1

Here you reassign x to point to an int object vith value 1. In other
words, x is no longer pointing to the same object as the first element
in the list test.

That is why get this:
test

test = [[1,2],[3,4]]
I need to do some data manipulation with the first list in the above
list without changing <test>
obviously x = test[0] will not work as any changes i make will alter
the original...

You make a slice, e.g.

x = [from:until:stride]

Now x is pointing to a new list object, containing a subset of the
elements in list. If you reassign elements in x, test will still be
the same.

The point to remember, is that a list does not contain values, but
pointers to values. This can be very different from arrays in C, VB,
Java or C#:

a = [1,2,3,4,5] in Python

is different from

int a[] = {1,2,3,4,5};

The Python statement makes a list of five pointers, each pointing to
an immutable int object on the heap. The C statement allocates a
buffer of 5 ints on the stack.

If you can read C, the Python statement a = [1,2,3,4,5] is thus
similar to something like

int **a, i, amortize_padding=4;
a = malloc(5 * sizeof(int*) + amortize_padding*sizeof(int*));
for (i=0; i<5; i++) {
a = malloc(sizeof(int));
*a = i;
}
 
C

castironpi

Coding to much in Visual Basic, like Fortran 77, is bad for your mind.

The distinction you're looking for is:

VB:
set a= collection
a= collection

Every assignment is a 'set'.
 

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
474,431
Messages
2,571,679
Members
48,796
Latest member
Greg L.

Latest Threads

Top