Page 1 of 1

this took me a full day to find

PostPosted: Mon Feb 26, 2018 10:46 pm
by kw123
Code: Select all
a=[1,2,3,4,5]
b=[]
for ii in range(100):
    b.append(a)
    b[-1][2]+=1

will change a[2]!!! from 3 to 3+1 ; 4+1;5+1 ...

though that "append()" would not just copy pointers to data but the data itself ..
this works correctly:
Code: Select all
import copy
a=[1,2,3,4,5]
b=[]
for ii in range(100):
    b.append(copy.copy(a))
    b[-1][2]+=1


The actual code a bit more complex but the principle in shown

Karl

Re: this took me a full day to find

PostPosted: Tue Feb 27, 2018 7:17 am
by DaveL17
As you found, append() wouldn't change the rule that a and b point to the same thing. With your corrected code, I get this:

Code: Select all
import copy
a=[1,2,3,4,5]
b=[]
for ii in range(100):
    b.append(copy.copy(a))
    b[-1][2]+=1

print(b)

>>> [[1, 2, 4, 4, 5], [1, 2, 4, 4, 5], ... [1, 2, 4, 4, 5]]
Are you looking to get 100 copies of a? You now have 100 separate lists within b. Consider this:

Code: Select all
import copy
a=[1,2,3,4,5]
b=[]
for ii in range(100):
    b.append(copy.copy(a))
    b[-1][2]+=1

b[-1][2]+=1
print(b)

>>> [[1, 2, 4, 4, 5], [1, 2, 4, 4, 5], ... [1, 2, 5, 4, 5]]

I'm curious why you would want 100 copies of list a. Maybe I'm misunderstanding something.

Re: this took me a full day to find

PostPosted: Tue Feb 27, 2018 7:55 am
by kw123
This was a simplified example The logic was several lines of code with several “if” date < xx and bin> yt etc
Just to illustrate the problem.


Sent from my iPhone using Tapatalk

Re: this took me a full day to find

PostPosted: Tue Feb 27, 2018 10:11 am
by jay (support)
The majority of objects in Python are passed around by reference rather than by value. copy.copy() works for basic objects, but for containers like lists and dictionaries (or objects which maintain references to other objects) it will just copy the container, but the objects will still be references.

Code: Select all
>>> a = range(0, 5)
>>> a
[0, 1, 2, 3, 4]
>>> b = range(5, 10)
>>> b
[5, 6, 7, 8, 9]
>>> c = [a, b]
>>> c
[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
>>> d = copy.copy(c)
>>> d
[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
>>> e = copy.deepcopy(c)
>>> e
[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
>>> c[0][0] = None
>>> c
[[None, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
>>> d
[[None, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
>>> e
[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
>>>


So, copy.copy(c) copies the array with references to the contained objects (represented by d). When we change one of the elements contained in c, the change is reflected in d. However, it's not reflected in e because we used copy.deepcopy(c), which attempts to make copies of all objects contained in the c container recursively.

Re: this took me a full day to find

PostPosted: Tue Feb 27, 2018 10:32 am
by matt (support)
And to further confuse the issue, note that indigo.List() and indigo.Dict() instances behave differently than python list/dicts in that they always return copies of the object and not references. More details are on this thread.

Re: this took me a full day to find

PostPosted: Tue Feb 27, 2018 1:30 pm
by DaveL17
Now you guys are just showing off. :wink:

Re: this took me a full day to find

PostPosted: Tue Feb 27, 2018 1:33 pm
by Colorado4Wheeler
If we want to show off we could start talking about super classes... :shock: :roll: :D

Re: this took me a full day to find

PostPosted: Tue Feb 27, 2018 11:18 pm
by kw123
replaced all copy.copy() with copy.deepcopy()

now I get:
Code: Select all
addToStatesUpdateList in Line '12682' has error='Pickling of "indigo.Device" instances is not enabled (http://www.boost.org/libs/python/doc/v2/pickle.html)'


one of the list elements is an indigo device. (>>dev<< from dev=indigo.device{123] )

code works fine with copy .copy() .. that does not complain as it does not try to do a deep copy of the indigo device I guess.

is there any other situation where copy. deepcopy() will not work?


Karl

Re: this took me a full day to find

PostPosted: Wed Feb 28, 2018 4:29 pm
by jay (support)
Yeah, deepcopy() on custom objects requires that the class implements the __deepcopy__ method. Indigo objects don't support that because they fundamentally are thin wrappers around C++ objects (and creating copies like that are not really possible).