Python List Issue

R

Robert Kern

Nick said:
I've hit a brick wall on something that I'm guessing is pretty simple but
it's driving me nuts. I noticed that with python lists, generally when you
make a copy of a list (ie, List1 = List2) List1 just becomes a reference to
List2 and any modifications done to List1 affects List2. Ok I can live with
this but I want to make a completely seperate copy not attached to the
original in anyway. So then I used this method. List1 = List2[:] . This
seemed to work in most situations, here I can modifiy List1 with out it
affecting List2. But now I've run into an odd problem, and I have no idea
why it's doing what it's doing.
Here's some code

#some globle varibles
bob = [[[0, 0]]]

I haven't gone through all of your code, but I suspect that the problem
is that objects in the list (in this case, other lists) don't get copied
only get referenced when you do bob[:]. This is expected.

See copy.deepcopy(). It will make sure that everything gets copied and
nothing just referenced (more or less).

http://docs.python.org/lib/module-copy.html

--
Robert Kern
(e-mail address removed)

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

Nick L

I've hit a brick wall on something that I'm guessing is pretty simple but
it's driving me nuts. I noticed that with python lists, generally when you
make a copy of a list (ie, List1 = List2) List1 just becomes a reference to
List2 and any modifications done to List1 affects List2. Ok I can live with
this but I want to make a completely seperate copy not attached to the
original in anyway. So then I used this method. List1 = List2[:] . This
seemed to work in most situations, here I can modifiy List1 with out it
affecting List2. But now I've run into an odd problem, and I have no idea
why it's doing what it's doing.
Here's some code

#some globle varibles
bob = [[[0, 0]]]
final = []

########################
def ApplySourceFunc(bob, final):
for I in range(1):

for I in range(len(bob)): #will go through the list and apply
ApplyOperatorsLoop(bob[:]) #all the operators to each rule in
the list creating a new list of rules

bob = final
final = []
#end ApplySourceFunc######

########################
def ApplyOperatorsLoop(aList):

iTemp = [] #initial temp, just for validity checking

iTemp = AddGetSpeed(aList[:])
if not iTemp == None: #if the operator returns None, then nothing of
value happend
final.append(iTemp)

#end ApplyOperatorsLoop####

#########################
def AddGetSpeed(tList):
ln = len(tList) #get the length of tList

if ln > 0:
if tList[ln-1][0] == 0:
tList[ln-1][0] = "GetSpeed()"
print "New Rule 'GetSpeed()' Added to the List"
return tList
return None
#end AddGetSpeed#########

So, here's what going on. ApplySourceFunc calls ApplyOperatorsLoop which
calls AddGetSpeed. Each function passes the list bob to the next fuction
using the [:] method. For some reason when I get to the AddGetSpeed method
and I do the assignment " tList[ln-1][0] = "GetSpeed()" " this directly
modifies the list bob. Ok, so i was annoyed by that since I was using the
whole [:] method as I passed and used the lists. Then I tried to insert a
temp list into the ApplyOperatorLoop function ( temp2 = aList[:]) and then
pass that into AddGetSpeed. Even when I did this AddGetSpeed modified the
orginial bob list. so, what I'm getting down to is:
How on earth can I make a complete seperate copy of a list with out it
being a attached to the original in any way shape or form so that I can
modifiy if at will and not worry about the original? I've tried every
combonation that I can think of to get this to work, I even wrote my own
copy function but even then I had the same trouble. Until this point
everything was going good, but this has really bugged me

Any ideas, suggestions, comments are greatly appreciated
thanks

Nick
 
N

Nick L

See copy.deepcopy(). It will make sure that everything gets copied and
nothing just referenced (more or less).

So far copy.deepcopy() seems to be working perfectly.
Thanks for the input

Nick
 
R

Ron_Adam

I've hit a brick wall on something that I'm guessing is pretty simple but
it's driving me nuts.

Yes, I've ran across that too a few times.
How on earth can I make a complete seperate copy of a list with out it
being a attached to the original in any way shape or form so that I can
modifiy if at will and not worry about the original?

This routine copies a list of lists.


# Makes a copy of a list of lists
# Containing simple data.
def copylistlist(alist):
if type(alist) is list:
copy = []
for i in alist:
if type(i) is list:
i = copylistlist(i)
copy.append(i)
return copy

bob = [[[0, 0]]]
final = copylistlist(bob)

print 'bob:'bob
print 'Final:'final


This still doesn't create new items within the new list. but with
literal data consisting of letters and numbers, it will work.

If you are working with a data tree, you may be able to modify this to
do what you want. Just add a test in the inner loop for the data you
want to modify.

Any ideas, suggestions, comments are greatly appreciated
thanks

Nick

Hope that helps.

Ron_Adam
 
N

Nick L

Thanks, thats a really handy function


Ron_Adam said:
I've hit a brick wall on something that I'm guessing is pretty simple but
it's driving me nuts.

Yes, I've ran across that too a few times.
How on earth can I make a complete seperate copy of a list with out it
being a attached to the original in any way shape or form so that I can
modifiy if at will and not worry about the original?

This routine copies a list of lists.


# Makes a copy of a list of lists
# Containing simple data.
def copylistlist(alist):
if type(alist) is list:
copy = []
for i in alist:
if type(i) is list:
i = copylistlist(i)
copy.append(i)
return copy

bob = [[[0, 0]]]
final = copylistlist(bob)

print 'bob:'bob
print 'Final:'final


This still doesn't create new items within the new list. but with
literal data consisting of letters and numbers, it will work.

If you are working with a data tree, you may be able to modify this to
do what you want. Just add a test in the inner loop for the data you
want to modify.

Any ideas, suggestions, comments are greatly appreciated
thanks

Nick

Hope that helps.

Ron_Adam
 
G

Greg Ewing

Nick said:
I noticed that with python lists, generally when you
make a copy of a list (ie, List1 = List2) List1 just becomes a reference to
List2 and any modifications done to List1 affects List2. Ok I can live with
this but I want to make a completely seperate copy not attached to the
original in anyway.

Although your immediate question has been answered (you wanted
a deep copy, not a shallow one), I think you should take a
step back and consider whether you really need to do that much
copying in the first place.

With the proper approach, I find it's extremely rare to need to
copy anything in a Python program, and rarer still to need
deep copying. Generally, it's better for a function not to
modify objects passed to it, unless that's the purpose of
the function. If a function needs a local copy of an argument,
it should create one itself, and not put the burden on the
caller.

Also, there are some things about your code that suggest you
still do not fully understand how scoping and assignment work
in Python:
def ApplySourceFunc(bob, final):
> ...
bob = final
final = []

These last two statements do not accomplish anything useful.
All they do is change which objects are referred to by the
parameter names 'bob' and 'final', which are local to the
function, and have no effect on anything outside it.
def ApplyOperatorsLoop(aList):
> ...
final.append(iTemp)
...

Here you are referring to the global variable 'final', not
the one passed as a parameter to ApplySourceFunc(). To get
the effect you seem to be after, you would need to pass
'final' on as a parameter to ApplyOperatorsLoop().

Here is how I would write this:

def ApplySourceFunc(bob, final):
for item in bob:
ApplyOperatorsLoop(item, final)

def ApplyOperatorsLoop(item, final):
new_item = AddGetSpeed(item)
if new_item:
final.append(temp)

def AddGetSpeed(tList):
if tList and tList[-1][0] == 0:
new_tList = tList[:]
new_tList[-1] = new_tList[-1][:]
new_tList[-1][0] = "GetSpeed()"
print "New Rule 'GetSpeed()' Added to the List"
return new_tList
else:
return None

Notice how all the copying is done inside AddGetSpeed(),
it only copies what is needed, and the fact that the copying
is needed is encapsulated within the function; its callers
don't need to know.

I have also made use of some other common Python idioms:

* Whenever possible, it is simpler and clearer to iterate
directly over the items of a list, rather than iterating
over its indices and then indexing it.

* Almost any object can be used as a truth value. Non-empty
lists count as true; empty lists and None count as false.

* The 'and' and 'or' operators short-circuit: if the first
operand determines the result, the second operand is not
evaluated.

* Negative list indices are counted from the end of the
list; e.g. aList[-1] means the last item of aList.

Hope that helps,
 

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,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top